Class constructors and Generics

The new great addition to the Delphi language in Delphi 2010 is the possibility to specify a class constructor and a class destructor to your class/record. I will not describe this feature in this post since you can see the online documentation for it on the Embarcadero Doc Wiki. The part I am interested in is the combination of class constructors and generics. As you might already know generic types aren’t really “run-time entities” but rather “compile-time” ones. This makes the initialization of “static” members of the type a bit more complicated. See for example this record:

type
  TMyType<T> = record
  private class var
    FSomeList: TList<T>;

  public
    ...
    ...
  end;

In this case the static FSomeList variable needs to be initialized to make sense. Normally, in non-generic classes, you would use the “initialization” and “finalization” sections to create and then destroy that variable. In generic classes this is impossible though. You have to get some workarounds (like initializing the list lazily), but you still cannot destroy the list on finalization.

Well, not anymore! Using class constructors and destructors allows you to easily initialize any static member of a type:

type
  TMyType<T> = record
  private class var
    FSomeList: TList<T>;
    
    class constructor Create;
    class destructor Destroy;
  public
    ...
    ...
  end;

class constructor TMyType<T>.Create;
begin
  // Executed on application initialization.
  FSomeList := TList<T>.Create();
end;

class destructor TMyType<T>.Destroy;
begin
  // Freed on application termination.
  FSomeList.Free;
end;

There is a catch tough. Since generic types are compile-time entities, any unit that uses a specialized generic type basically defines that type in itself. For example if you use TList<String> in four of your units, all four units will internally declare the TList<String> class. This results in the TList<T>‘s class constructor to be executed four times – once per unit. This is expected behavior since each type specialization has different static members. For example:

type
  TDistinctType<T> = record
  private class var
    FMarker: Integer;

    class constructor Create;
  end;

If TDistinctType<String> is used in multiple units, each unit’s version has it own FMarker, which means it needs to be initialized for each unit.

The conclusion — be aware that class constructors and destructors for generic types may execute multiple times.

15 Responses to 'Class constructors and Generics'

  1. Moritz Beutel says:

    > You have to get some workarounds (like initializing the list lazily), but you still cannot destroy the list on finalization.

    It’s possible to destroy class vars on finalization; by using an interface type as class var.

  2. alex says:

    Yes, true, somehow I never thought about that :)

  3. Anonymous says:

    >class constructor TMyType.Destroy;

    I would think Destroy is a class destructor, not a class constructor

  4. alex says:

    Thanks, I fixed the code. Was in a rush and just c/p-ed some code :)

  5. alex says:

    Yes, it seems that class ctors/dtors are not executed for the specialization in the main .dpr of generic type. For specializations made in other units it will get executed.

  6. steve says:

    Hi Alex,

    you should add “.Create” to the constructor’s body statement ;-)

  7. delphigeist says:

    Alex, 2 weeks and no post what’s happening?

  8. alex says:

    Lots of work around here.

  9. delphigeist says:

    Well I can’t wait to see a new interesting post!

  10. tutaj says:

    Ogromne dzięki za ten pomocny wpis, oby tak dalej

Trackbacks/Pingbacks
  1. [...] See more here:  Class constructors and Generics | YAPB [...]

  2. [...] himitsu: Ist das'n Bug in Verbindung mit den Generics? Vermutlich, Alex Ciobanu hat dazu mal was geblogt. [...]

Leave a Reply

Your email address will not be published.