Add an array property enumerator in FPC/Lazarus

I’ve been wishing object pascal supported array property enumeration for a long time:

  TTest = class
    // ...
    property Objects[Index: Integer]: TObject read GetObject;
  end;
var
  Test: TTest;
  Obj: TObject;
begin
  //...
  for Obj in Test.Objects do
    //...
end;

Unfortunately, this should not be possible because enumerators can be defined only with the GetEnumerator function in class/record/interface and other types through helper classes.

This is the case in Delphi.

I discovered a bug in FPC that allows to declare an enumerator for an array property. Studying the FPC code, I found out that it does not check if the array property parameters match the property definition. Instead it checks whether an (overloaded) getter function with the supplied parameter set exists. So you create a second parameterless getter function that returns the enumerator and, voila, your “for Obj in Test.Objects do” loop compiles!

  TTest = class
    // ...
    // usual getter
    function GetObject(Index: Integer): TObject; overload;
    // overloaded getter used for the enumerator
    function GetObject: TTestObjectEnumerator; overload;
    property Objects[Index: Integer]: TObject read GetObject;
  end;

TTestObjectEnumerator can be either a class or record – FPC frees enumerators automatically. But there is one thing you have to do in contrast to usual enumerators – you obviously have to define TTestObjectEnumerator.GetEnumerator that returns Self so that the compiler finds the GetEnumerator function (thanks Sven Barth for the idea).

What are the benefits of having such an array property enumerator? Clear and understandable code and also the ability to have enumerator for every array property within an object. As an example consider this code:

procedure TForm1.Check;
var
  Comp: TComponent;
begin
  for Comp in Self do
    // ...
end;

From my POV it’s quite unclear what collection is used for the enumerator. The default enumerator can even be overloaded with a helper, which can lead to unpredictable results.

With the array property enumerator, the code is much clearer and you can use more enumerators in the same object:

procedure TForm1.Check;
var
  Comp: TComponent;
  Cont: TControl;
begin
  for Comp in Components do
    // ...
  for Cont in Controls do
    // ...
end;

Download the example code PropArrayEnum.zip:
arraypropenum.lpr: enable property array enumerator in your own class.
tobjectsenum.lpr: enhance TStrings.Objects with an enumerator (with a helper class).

Further reading:
feature request report
fpc-devel thread 1
fpc-devel thread 2 (a), fpc-devel thread 2 (b)

Procedure call with delay in Delphi and Lazarus

With the latest threading library from Delphi XE7, it’s been quite easy to start a procedure with a delay. The TTask does its job very well:

  TTask.Create(
    procedure
    begin
      Sleep(1000);//delay of 1s
      ShowMessage('Hello');
    end).Start;

This is very easy but it has one big issue – you cannot easily stop the execution before the delay limit is reached and it can be used only in the latest Delphi versions. So I came up with my own alternative:

  TOCallWithDelay.Create(Self, 1000,
    procedure
    begin
      ShowMessage('Hello');
    end);

The first parameter is the component owner – if the owner is destroyed (e.g. you close the dialog before the limit), the procedure call won’t be executed. The class works in Delphi 5 and newer on all supported platforms, including mobile/ARC. FPC/Lazarus is supported as well.

If you want to stop the object in the future, use:

procedure TForm1.Btn1Click(Sender: TObject);
var
  xCall: TOCallWithDelay;
begin
  TOCallWithDelay.Create(Self, @xCall, 1000,
    procedure
    begin
      ShowMessage('Hello');
    end);

  xCall.Free;//stop TOCallWithDelay -> do not call the method
end;

Download the source code with a simple test project:
OCallWithDelay.zip

OXml left beta

Yesterday, I finally released OXml 1.0, the first version in production state and OXml definitely left beta. What changed for you as an OXml user?

The most important change is the license. OXml is now licensed under CPAL 1.0. It is an open-source license with a strong attribution clause. It forces you to display the Original Developer’s Attribution Information each time an executable is launched. As an alternative, you may buy a commercial license which doesn’t require any attribution at all.

I prepared a PLUS package with extra units: two XML serializer/deserializers, one based on TypInfo (for Delphi 6+ and Lazarus) and one based on enhanced RTTI (for Delphi 2010+). I also plan writing a dataset-to-XML component. This package will be available only for customers who bought OXml.

What led me to the decision to change the license was first the fact that there are a lot of free XML libraries but I believe that OXml is special and those who really need OXml should also be willing to pay a reasonable amount for it. As a result I’ll be motivated to keep updating and enhancing OXml. Those who don’t want to pay for OXml can use one of its beta versions licensed under MPL, be pirates and ignore the new license or switch to other XML libraries.

Second it’s Embarcadero’s own update policy. I have to pay anually for Delphi license as well so a small fee for OXml helps me keep OXml updated in future Delphi versions as well.

OXml homepage: http://www.kluug.net/oxml.php

Ansi- and RawByteString for Delphi mobile

Do you want to use 8-bit strings on mobile platforms with all the nice old-fashioned features?

ORawByteString has been designed to make old code easily portable to mobile platforms – you only have to rename functions like “Copy” to “AnsiCopy”, that’s all.
With ORawByteString you can write code like this:

procedure TestAnsiString(const aOutputLines: TStrings);
var
  Raw: RawByteString;
  Wide: string;
  I: Integer;
  C: PAnsiChar;
begin
  Raw := RawByteString('HEADET');
  Raw[AnsiLength(Raw)] := AnsiChar('R');//Raw = HEADER
  Wide := UTF8ToString(Raw);//convert "HEADER" from UTF-8 (ASCII) to UTF-16

  aOutputLines.Clear;
  aOutputLines.Add(Wide);//output "HEADER"

  Raw := RawByteString(Wide);//CONVERT UTF-16 back into ASCII (without any codepage)
  I := Pos('H', Raw);//Fast search in RawByteString
  Raw := AnsiCopy(Raw, I, 3);//Use fast copy on RawByteString -> Raw = "HEA"
  Wide := String(Raw);//CONVERT ASCII to UTF-16 (without any codepage)

  C := PAnsiChar(Raw);//YOU CAN EVEN USE PAnsiChar!!!
  Raw := RawByteString(C);//AND convert PAnsiChar back to RawByteString/AnsiString

  C := PAnsiChar(Raw);
  aOutputLines.Add(String(C[2]));//output "A" (the third letter from C (PAnsiChar is always 0-based)

  AnsiDelete(Raw, 1, 1);//Fast delete in RawByteString -> Raw = "EA"
  AnsiInsert(RawByteString('x'), Raw, 2);//Fast insert -> Raw = "ExA"
  Raw := UpperCase(Raw);//Fast uppercase -> Raw = "EXA"
  aOutputLines.Add(String(Raw));//output "EXA"
  Raw := LowerCase(Raw);//Fast uppercase -> Raw = "exa"
  aOutputLines.Add(String(Raw));//output "exa"
end;

ORawByteString.pas allows you to:

  1. use 8-bit AnsiString and RawByteString on mobile platforms.
  2. use 8-bit PAnsiChar on mobile platforms.
  3. use 8-bit AnsiChar on mobile platforms.
  4. use the same AnsiString code on desktop and mobile.
  5. -> no IDE hacking is needed :)

It features it’s own text functions like AnsiInsert(), AnsiCopy(), AnsiDelete(), AnsiLength(), Pos(), LowerCase() etc. to offer maximum performance.

And when we talk about performance: ORawByteString is in some scenarios a little bit slower than string on mobile platforms, but most of the test cases and an usual usage showed no significant performance drawbacks. String operations perform on ORawByteString as fast as on string.

ORawByteString features full copy-on-write, mutability and all string features you have always taken advantage of.

On the one hand ORawByteString is a technical exhibition on how you can use records with operators to create your own delphi type, but on the other hand it can also be useful since it’s not certain that 8-bit strings will be officially available on mobile platforms at some point.

License: MPL 1.1 http://www.mozilla.org/MPL/1.1/

Download: http://www.kluug.net/orawbytestring.php

Free() bug on mobile compilers

Some time ago, we discussed the Free/DisposeOf issue of new ARC Delphi objects in the Delphi plus group.
The problem is that Free() does not call the destructor directly any more. It sets the object reference to nil instead. When the reference count is 0, the destructor is called.

I am among those who don’t like this new compiler feature. Free could just do what DisposeOf does (call destructor and set the object to zombie state). So there is basically no need of DisposeOf.

Now, we have another argument for the DisposeOf/Free futility: under some circumstances, pending references can be created by the compiler itself (when the object reference is passed to the Result variable but not used at all). The programmer thinks that there are no references left and the destructor should get called but no, the destructor is not called indeed.

The same behaviour can be observed on desktop compilers too with all reference-counted types (strings, interfaces, dynamic arrays) but none of those types rely on an explicit destructor call, so it does not really matter.

Link to the QC: http://qc.embarcadero.com/wc/qcmain.aspx?d=124017

Honestly, I just don’t see the point why I should call DisposeOf() now everywhere where I have called Free() for so many years…

Sample code to reproduce (call TestReferenceBug()):

type
  TMyObject = class(TInterfacedObject)
  public
    destructor Destroy; override;
  end;

destructor TMyObject.Destroy;
begin
  ShowMessage('TMyObject.Destroy');

  inherited;
end;

function MyFunc(const aObj: TObject): TObject;
begin
  Result := aObj;
end;

procedure TestReferenceBug;
var
  xObj: TObject;
begin
  xObj := TMyObject.Create;
  try
    MyFunc(xObj);//"virtual" reference is created here
  finally
    xObj.Free;//xObj.Destroy is not called!!!
  end;

  ShowMessage('After try-finally-end');

end;//"virtual" reference is destroyed here -> call xObj.Destroy