3

I have a following definition.

type
  TOmniTaskDelegate = reference to procedure(const task: IOmniTask);

What type of container should I use (should be supported in D2009) to store a list of TOmniTaskDelegate instances? Currently I'm using array of TOmniTaskDelegate but I'm not really happy with that.

gabr
  • 26,580
  • 9
  • 75
  • 141
  • Why aren't you happy with the array? – Lasse V. Karlsen Jul 26 '11 at 11:59
  • a) Because I would like to delegate the responsibility to a container with well-defined interface and b) because I now resize the array every time I add something to it. True, I could write a nice wrapper around the array which would know the current size and allocated size etc but then I'm already re-implementing TSomeList and I'd rather use something provided with Delphi (assuming such thing exists). – gabr Jul 26 '11 at 12:01
  • 2
    What is `TSomeList`? Couldn't you just use `TSomeList`? – David Heffernan Jul 26 '11 at 12:10
  • TSomeList = either TList, TObjectList or TIDontKnowWhatElseIsSupportedInD2009List – gabr Jul 26 '11 at 14:57

2 Answers2

8

I would use TList<TOmniTaskDelegate>. Since this is typesafe due to the use of generics, it will correctly handle the lifetime issues of its members.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • 1
    I'm thinking of `TList` in Generics.Collections. This does deal with the reference counting because it is typesafe. But now I have a nagging doubt that it may not be included in D2009. – David Heffernan Jul 26 '11 at 12:08
  • TObjectList is not the proper container since anonymous methods references need to include a reference to the method as well as a reference to the "self" of the interface. In other words the size would be 2 x SizeOf(Pointer). – Cosmin Prund Jul 26 '11 at 12:11
  • @Cosmin That's just a silly mistake, I meant `TList` of course. – David Heffernan Jul 26 '11 at 12:12
  • 1
    +1. Apparently the generic `TList` *is* available in Delphi 2009. No need to re-invent the wheel: the generic list is implemented using `array of` so it's guaranteed to be properly finalized and type safe. – Cosmin Prund Jul 26 '11 at 12:15
  • Beware of the situation where you want to remove something from the list by specifying a reference. I once ran into a situation where items weren't removed because Delphi created a different magic auto-anonymous-method-wrapper every time, even for the same methods. – Heinrich Ulbricht Jul 26 '11 at 12:21
  • 1
    @Heinrich That's because it was a different reference. Remember that anonymous methods have variable capture. – David Heffernan Jul 26 '11 at 12:23
  • 1
    @David Adding the same `method of object` multiple times also gives different references. This took me by surprise the first time I encountered it. I thought they would be the same. – Heinrich Ulbricht Jul 26 '11 at 13:59
  • @Heinrich OK, I can see how `method of` could be different from `reference to`. – David Heffernan Jul 26 '11 at 14:07
3

Edit: Delphi 2009 includes the generic TList<T>, I assume it's implemented using array of, just as the one in Delphi 2010. That makes the TList<T> the optimal choice! My original answer stays because it explains why array of is a great data structure and why not using it is a lot of trouble.


Your choice of array of Anonym looks very good to me because:

  • Anonymous methods are managed entities (implemented using interfaces). They need to be properly finalized.
  • The dynamic array is itself a managed type, making sure the anonymous method references are properly finalized.
  • Delphi 2010 generic containers are implemented using dynamic arrays, so they're up to the task. But make sure you don't grow your arrays one-by-one, grow in chunks.

If you use anything else for the implementation you'll need to take care of finalizing the references yourself. Examples:

  • If you use plain blocks of memory you'll need an destructor that deliberately sets each item to nil (ie: not ZeroMemory or FillChar) so the compiler gets a chance to generate finalization code.
  • Records are managed objects, and they could hold references to dynamic methods, but they can only hold a finite number of references, if you need more you'll need to implement a sort of linked list and then you'll need to carefully manage there life cycle.
  • Classes suffer all the deficiencies of records, and they add their own layer of overhead on top of that.
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
Cosmin Prund
  • 25,498
  • 2
  • 60
  • 104
  • 1
    In your case you are implementing a fundamental type (a fundamental new type of list) and I do not believe that the generics and compiler can be trusted not to do something that would mess up the procedure references. If I was going to use something other than array-of-ProcRef then I would use a TList and put the procedure reference inside the record type. – Warren P Jul 26 '11 at 12:11
  • 1
    `array of` is fine for the private implementation of a list, but I would never wish to use it as a primary data type. If you can't use `TList` then create your own lookalike. – David Heffernan Jul 26 '11 at 12:13