Archive

Archive for the ‘Ideas’ Category

What client-side platforms do you develop for?

March 26th, 2013

What client-side platforms do you develop for? With Delphi/FreePascal or with other tools.

This is a small poll to gauge the audience of this website, check all applicable, but please limit yourself to those you personally develop for (be it work or hobby), not your company or colleagues.

What client-side platforms do you develop for?

  • Windows 32bits (95%, 413 Votes)
  • Windows 64bits (55%, 239 Votes)
  • Linux (14%, 59 Votes)
  • Microsoft .Net (16%, 70 Votes)
  • HTML5 / JavaScript (33%, 143 Votes)
  • Android (22%, 96 Votes)
  • iOS (16%, 71 Votes)
  • OS X (11%, 46 Votes)
  • WinRT (4%, 18 Votes)
  • Java (7%, 29 Votes)

Total Voters: 437

Loading ... Loading ...

Ideas

Pascalish-looking generics poll

November 21st, 2012

Now for a bit of hypothetical polling! thinking on the generics/templates syntax, one can’t quite shake the feeling Delphi got the C#/C++ generics/templates syntax. The  < and > can’t be read out loud, and just look like an out of place reuse of the comparison symbols.

Interestingly enough, Pascal had something of a generics syntax (if in a restricted case) with “array of”. I sometimes wonder how reusing that syntax would float, especially combined with some other enhancements f.i. instead :

TQueue<T> = class
var myQueue : TQueue<T>;
myQueue := TQueue<T>.Create;
function Whatever<T>(param : T) : String;

could be more Pascalish (and readable) as

TQueue of T = class
var myQueue : TQueue of T;
myQueue := new TQueue of T;
function Whatever of T(param : T) : String;

And for multiple types with constraints, instead of

TFoo<T: ISerializable; V: IComparable>

wouldn’t something like

TFoo of T (ISerializable), V (IComparable)
// or (Kazantsev Alexey's)
TFoo of (T : ISerializable, IWhatever; V : IComparable)
// or (Schalk's)
TFoo of T, V
where T is ISerializable
where V is IComparable

be more Pascalish?

The clock can’t really be turned back… but what say you?

Pascalish generics syntax

  • I prefer C-style anyway (40%, 69 Votes)
  • I prefer Pascalish style (60%, 103 Votes)
  • I've got a better idea (0%, 0 Votes)

Total Voters: 172

Loading ... Loading ...

Ideas , ,

Mutant records: on methods (and helpers)

May 7th, 2012

When “record with methods” were introduced, an important feature was overlooked: mutability. This article discusses the problem, and introduces a possible syntax extension to solve it. Ideas & comments welcome!

The Problem

Effectively, “records with methods” treat all record “const” elements as “var“, even when they shouldn’t, and effectively ignores the compiler option “assignable constants”. Witness the following record:

type
   TRec = record
      Field : Integer;
      procedure IncMe;
   end;
...
procedure TRec.IncMe;
begin
   Inc(Field);
end;

Then the compiler will happily allow you to do:

const MyNullRec : TRec = (Field: 0);
...
MyNullRec.IncMe; // watch me, I'm magic!
WriteLn(MyNullRec.Field); // will write 1 !

…it will also accept…

procedure Myproc(const r : TRec);
begin
   r.IncMe; // modified whatever r as if it had been a var
end;

…and that as well…

type
   TMyClass = class
      private
         FRec : TRec;
         procedure SetRec(const aRec : TRec);
      public
         property RW : TRec read FRec write SetRec;
         property RO : TRec read FRec;
   end;
...
var myClass : TMyClass;
...
// everything's as it should be there
myClass.RO := aRec; // gives an error
myClass.RW := aRec; // uses SetRec
// but that compiles to...
myClass.RO.IncMe; // modifying a read-only property !
myClass.RW.IncMe; // modifies and bypasses SetRec !

It would “compile” even if the getter was a function returning a record… or just in about any case, really.

And of course you can cascade all the above in a real-world case, so you end up with weird side-effects and really hard-to-track down bugs.

Besides bug, that also raises the issue of usability of records like TPoint and other simple vector/matrix types, as properties of objects. As long as they did not have methods, you would have to use the setter to modify such a property, so the objects had guaranteed notification of a position change f.i., with methods being able to magically mutate the records, you no longer have that guarantee. And adding all the baggage so that a TPoint can be owned and notify its owner of a change would be over-the-top, wouldn’t it?

What’s Missing

Two syntax elements are missing:

  • the ability to specify if a method is mutating the record or not, ie. if it should get “Self” as a “var” or as a “const“, so that you can make the above behavior explicit, and the compiler can emit errors when it’s not appropriate
  • the ability to mark a record as mutable/immutable, to further remove the ambiguities

Ideas for such a syntax, in explicit form, and reusing existing keywords:

type
   TRec = record
      Field : Integer;
      var procedure IncMe; // mutating
      const function ToString : String; // non-mutating
   end;

Modifiers in Pascal (except “class“) usually follow the declaration, but “var” and “const” can’t, as they could be ambiguous with the declaration of a following constant/variant. So if reusing those, rather than introducing new keywords, they have to be in front.

Also you could mark a record as explicitly mutable or immutable, by prefixing it with “var” or “const”

type
   TImmutableRec = const record
      Field : Integer;
      var procedure IncMe; // mark as explicitly mutating ?
      function ToString : String; // non-mutating by default
   end;
   TMutableRec = var record
      Field : Integer;
      procedure IncMe; // implicitly mutating
      const function ToString : String; // mark as explicitly non-mutating
   end;

For backward compatibility with existing records with methods, the implicit default would have to be “var record” as the records are currently all mutable.

With that extra information, the compiler could then perform proper checks and proper parameter passing, so the side-effects mentioned could happen only if you explicitly went for them, rather than by mistake as is currently the case.

Additionally, immutable records would implicitly have their fields as read-only everywhere outside the record constructor (which would then become truly useful as language syntax element). It might also be possible to extend the syntax to be able to declare explicitly immutable classes.

The case of helpers

When generalizing helpers (as in DWScript), the above mutability issue also applies to helpers for value types, ie. records and static arrays, so a similar syntax would have to be introduced.

To minimize side-effects, helpers on record and static arrays currently pass their “Self” as const, this allows to use such helpers in all cases (including “const” parameters, function results, read-only properties…), but is restrictive, as it prevents mutation. So once the above syntax is decided upon, it could apply to them as well.

For helpers on reference types in DWScript (classes, interfaces, dynamic arrays), the issue doesn’t apply.

Note that in Delphi, helpers also have the design bug of being able to magically access private fields… but that’s another story.

 

Ideas , , , , , ,

Old School Maze Pascal to JavaScript

March 13th, 2012

Zarko Gajic recently reposted Kostas Symeonidis’s Maze, this is an old code (2004) that generates a random maze using Prim’s algorithm and solves it.

I wondered how it would hold its own when compiled to JavaScript, and by that I mean compiling the old 2004 source… click on the picture to the right to run a version compiled with SmartMobileStudio. Works in all the usual desktop and mobile suspects. Click or touch the maze to solve between arbitrary locations.

The original source works on a large static array that is passed as var parameter and where the bytes are used in a bitwise fashion. All in all it does its job in a brute-force native-compiler friendly way, but is quite suboptimal for a JS execution. Anyway I compiled as close as possible to the original (update source zip, 6kB).

Very few changes were required to get it to compile:

  • changed the TObjectList to an “array of TCell
  • replaced Random() with RandomInt()
  • replaced the FillChar() with nested loops
  • mapped TCanvas to TW3Canvas

But the bulk of the code compiled without changes, and runs in Android, Chrome, IE9, etc. (only FireFox has a glitch, which is not related to the Maze code, but to the VJL and a Mozilla event name).

Ideas

What do you use for String localization in Delphi?

February 15th, 2012

Delphi an an ITE for localization (of which I’m not a fan), we’ve been using something very similar to gnu gettext where I work (and I like it), what other String or screen localization tools have you been using and recommending?

You can vote for multiple options, and suggest new ones in the comments!

What do you use for string localization in Delphi?

  • Delphi's Integrated Translation Environment (6%, 9 Votes)
  • GNU gettext / dxgettext (30%, 47 Votes)
  • Other (suggest it in comments) (15%, 24 Votes)
  • TsiLang (13%, 20 Votes)
  • Multilizer (7%, 11 Votes)
  • Localizer (8%, 12 Votes)
  • Interkodex (0%, 0 Votes)
  • Helicon Translator (0%, 0 Votes)
  • Sisulizer (16%, 26 Votes)
  • Plain old .INI files (7%, 11 Votes)
  • DKLang (1%, 2 Votes)
  • Kryvich’s Delphi Localizer (1%, 2 Votes)

Total Voters: 158

Loading ... Loading ...

Ideas

What do you think of function overloads?

January 26th, 2012

In Delphi, you can overload functions, but doing so requires using the overload directive explicitly, f.i. the following code declares two functions with the same name, one that will be invoked if you pass an integer, another that will be invoked you pass a string:

function MyFunc(a : Integer) : String; overload;
function MyFunc(s : String) : String; overload;

In many other languages, the overload directive is implicit, you don’t have to type it and you can always overload. On the other hand, it means that as long as your parameters differ, you can end up overloading an existing function without noticing, which can lead to confusion.

What do you think of function overloads?

  • They're confusing, they shouldn't be allowed. (3%, 11 Votes)
  • They can be useful, but should be explicit via a directive. (72%, 246 Votes)
  • They're very useful, no directive should be required. (25%, 85 Votes)

Total Voters: 342

Loading ... Loading ...

Ideas ,

Zero-based Strings indexes?

December 15th, 2011

In a now infamous and enormous thread I won’t name, Allen Bauer dropped a bomb:

<bomb>Oh, and strings may become immutable and 0-based ;-)…</bomb>

Currently Oxygene has zero-based strings, I was considering it for DWScript too, but the backward-compatibility implications are a bit too huge (yes, we and customers have many years of accumulated DWS code), and the kind of issues triggered by that are hard to track/fix/warn about… or are they?

One evolution that is looming (at least for DWS, can’t speak for Delphi) is having methods on base-types too, since these would be new methods, with no legacy, a zero-based convention could be introduced there, f.i.:

sub := Copy(str, 1, 10); // legacy, 1-based
sub := str.Copy(0, 10); // new, 0-based

As time passes, the functions would be marked as “deprecated”, and code migrated over to methods incrementally. The interim time would of course be a mess mix of zero and 1-based conventions… not very desirable, but certainly preferable to breaking code in non-obvious ways.

One hard case (without easy compiler-warnings) that would remain would be that of indexed character access, like “str[i]“. I can think of only one safe way around that one: not having a default array property. That could however be leverage to gain some, f.i.:

char16 := str.Char16[i]; // equivalent to old str[i]
code := str.Code16[i]; // equivalent to old Ord(str[i])
charStr := str.Char[i]; // new, retrieves the whole character (1 one or more char)
codePoint := str.Code[i]; // new, retrieves the whole unicode codepoint

The Xxx16 versions would return a a WordChar, equivalent to a current Char, and only capable of holding a character from the BMP. The Xxx version would return a String (a whole Unicode character/codepoint) or an UTF32 code.

Comments? Other Ideas?

Ideas , , ,

Taming the flock with Object Pascal

September 28th, 2011

And now for a more interactive demo than last time, this is a full-screen HTML5 Canvas interactive demo with the source in Object Pascal, compiled to JavaScript by the DWScript JS CodeGen. Click below to see it in action and hit F11.

Click-me, I'm best seen in action!

It illustrates using records, classes, and invoking the HTML5 Canvas and jQuery directly from Pascal code.

Chrome handles it best, but IE9 and FireFox are doing reasonably fine.

This time, I’ve wrapped it up in a demo zip (653 kB), where you can have a look at the DWScript code, the Delphi code required to compile & run the demo, and you can even fiddle with the source and over-simplified compiler options (Debug/Release/Obfuscated) with the included pre-compiled executable.

To compile the demo yourself, you’ll need DWScript (SVN version), SynEdit (SVN version) and Indy (the version included with Delphi XE should be okay), which is used for a mini-web server to allow running the demo directly in your favorite browser.

Ideas ,

How would you name TObject’s ancestor class?

June 23rd, 2011

I’m looking for a good name for a “TObject ancestor” class, that would introduce no Pascal baggage: no “Create”, no “Destroy”, no “Free”, etc.
TObject would become a subclass of that root class.

A good name would have to be meaningful as being the “true” root of the class hierarchy, and ideally, it would have to be a name unlikely to conflict with existing class names in existing code (so TRootObject, TBaseObject, etc. likely don’t cut it).

The underlying purpose would be to allow integrating everything in the class system, including objects defined in other languages, and seeing them as objects rather than interfaces (which have a baggage of their own), ie. allow them to have directly accessible fields, allow subclassing, etc.

Any good name ideas?

edit 06-24: Thanks! Quite a lot of comments and suggestions! ;-)

To clarify things a bit, the TDWSxxx suggestions are interesting, but semantically-speaking, a TObjet in DWS is an actual DWS object. Also the “ancestor of TObject” would be used to bring in f.i. Java objects, for which TObject methods like .Free or .ClassType f.i. either don’t have a meaning, or would have a different one. One way could be to make all TObject methods virtual and raise exceptions when they’re meaningless, but that would be a runtime solution to what is a compile-time problem.

All this might be a bit fuzzy, as it revolves around things brewing in the lab, and should become clearer in a few weeks time!

FWIW an ancestor of TObject could also be useful in Delphi for special purposes, and could serve as basis for non-reference-counted interfaces (f.i. if you were to introduce a garbage-collection in Delphi).

Ideas

Poll: dynamic arrays as reference or value type?

June 15th, 2011

Here is a small poll to help me decide in which direction to go about dynamic arrays in DWScript. The poll is at the bottom of the post, to encourage reading before voting ;-) .

The Problem

In Delphi, fixed-size arrays behave as value types, while dynamic arrays behave as reference type, this can be illustrated by:

type
   TFixedSizeArray = array [0..9] of Integer;
   TDynamicArray = array of Integer;
...
procedure SomeProc(fixed : TFixedSizeArray; dynamic : TDynamicArray);
begin
   fixed[0]:=2;
   dynamic[0]:=2;
end;
...
var
   f : TFixedSizeArray;
   d : TDynamicArray;
begin
   f[0]:=1;
   SetLength(d, 10);
   d[0]:=1;
   SomeProc(fixed, dynamic);
   // at this point f[0] is still 1, but d[0] is now 2
end;

However if you change SomeProc to

procedure SomeProc(fixed : TFixedSizeArray; dynamic : TDynamicArray);
begin
   fixed[0]:=2;
   SetLength(dynamic, 20);
   dynamic[0]:=2;
end;

then d[0] will be unchanged, as the SetLength() call will have spawned a different dynamic array, if you want to resize a dynamic array you have to pass it as a var parameter, while if you only want to change the items, you don’t…

With current Delphi syntax, dynamic arrays are schizophrenic: they are passed by reference, like a TObject would be, but resized as value types.

In a way, dynamic arrays borrow the String type’s SetLength() syntax and behavior, but String is passed in a form that mimics a value type, in the example above, it would behave like TFixedSizeArray, ie. if you modify a String that wasn’t passed as var in SomeProc(), the original variable won’t be changed.

The Options

To rationalize the situation, there are two options:

  • make dynamic arrays a value type, with similar copy-on-write optimization as String to minimize unnecessary copies. A side benefit is that it makes dynamic arrays behave similarly to fixed-size arrays, all would behave as value types, a downside is a performance hit on write accesses (for the copy-on-write mechanism).
  • make SetLength() treat dynamic arrays as a 1st-class reference type, ie. have it work as dynamic.SetLength() would, and if you need to make a unique copy of a dynamic array, you would use a dedicated function like Copy() rather than piggyback SetLength().

So, what would feel more natural to you?

Dynamic arrays would be better as...

  • a value type, like non-dynamic arrays, minimize the surprise factor (38%, 22 Votes)
  • a full self-respecting reference type, more practical and efficient (62%, 36 Votes)

Total Voters: 58

Loading ... Loading ...

Ideas