Duck Typing in Delphi

"The Delphi ORM", Delphi XE2, Programming, Uncategorized Add comments

During a new dorm feature development, I’m faced a nice problem:

I want to have a generic access to a “kind” of list

Let’s say:

  1. procedure DoSomething(Obj: TMyListType);
  2. begin
  3. end;

But, I want to have that generic access without a Layer Supertype object, because I need to be able to use objects from other libraries or 3rd party. In this case traditional polimorphism is not usable, so I’ve opted for an interface…

  1. procedure DoSomething(MyIntf: IMyListInterface);
  2. begin
  3. end;

Cool, but I want to have that access without any change to that object. So implement an interface is not a viable solution. This is particulary true because the generics data structure in Delphi do not implement an interface. Will be nice to have a fully interfaced list and dictionaries in a future Delphi version.

So, how I could implement a generic access to a generic list?

  1. procedure DoSomething(MySomething: ???);
  2. begin
  3. end;

However, operations on that list are few and well known, so I’ve opted for a “DuckTyping“.

Introducing The Duck

Introducing The Duck

The name of the concept refers to the duck test, attributed to James Whitcomb Riley, which may be phrased as follows:

“When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.”

So, in my case, I’ve created an Adapter object wich adapts the external interface (few, well know operations) to the “duck” inside it.

The adapter is useful because I can use the compiler checking that the RAW RTTI access doesn’t allow.

Write an “RTTI adapter” using the new Delphi RTTI, is very simple. This is the code of the class TDuckTypedList that allow to use any object as a “list”. How I can define that the object is actually a list?

The criteria is:

If the object has
- An “Add” method with one parameter of type TObject (or descendant);
- A “Count” property;
- A “GetItem” method that have an integer parameter and return an object;
- A “Clear” method;
then, that object is a list.

So I can write the following:

  1. DuckObject := TDuckTypedList.Create(Coll);  //the adapter
  2. for x := 0 to DuckObject.Count - 1 do
  3.   DoSomething(DuckObject.GetItem(x));

I’ve done some speed tests comparing this way to the classic static way, and the speed is almost the same because the RTTI lookup is cached in the constructor of the adapter. So, so far so good.

This solution is already in use inside the dorm code in a feature branch.

Full code is available in the dorm SVN

Any comments?

9 Responses to “Duck Typing in Delphi”

  1. Stefan Glienke Says:

    This will not work for the built-in list types in Generics.Collections because GetItem is private and RTTI cannot access it (unless you recompile and change the RTTI visibility directives). With XE2 you should be able to get RTTI for the Items property.

    Also with XE2 it is possible to do full duck typing without creating the class behind the interface and therefor in theory duck type everything to any interface. I wrote about it on my blog while ago.

  2. Daniele Teti Says:

    @Stefan Glienke
    Stefan, this code works with the Generics.Collections in Delphi XE2 Update 2. Check the dorm code in SVN.

    This is a small sample that prove that TList.GetItem is visibile by the RTTI:


    procedure TForm11.FormCreate(Sender: TObject);
    var
    List: TList<string>;
    ctx: TRTTIContext;
    RttiType: TRttiType;
    begin
    List := TList<string>.Create;
    try
    List.Add('Hello World');
    ctx := TRTTIContext.Create;
    try
    RttiType := ctx.GetType(List.ClassInfo);
    ShowMessage(RttiType.GetMethod('GetItem').
    Invoke(List, [0]).AsString);
    finally
    ctx.Free;
    end;
    finally
    List.Free;
    end;
    end;

    For the 2nd observation, I didn’t understand your point. Can you explain me?

    UPDATE:
    I saw your DuckTypingSample. It is ok for this simple case, but is not an Adapter. What I’d like to have, is a real adapter (adapts one interface to another, not that extract an implenentation of an interface) that could have also a “list” of possibile method to bind to each declared method. e.g. “Count” on some lists could be a method and not a property so in the Contructor I can “search” of an available method to recocnize my duck. (First search for a “Count” property, if there isn’t search for a “Count” method… and so on)

  3. Eric Says:

    Your sample doesn’t compile, you add a string to TList.
    But when fixing that, it doesn’t run: GetMethod(’GetItem’) returns nil…

  4. Daniele Teti Says:

    @Eric
    The code is for Delphi XE2 Update 2. In Delphi XE it compiles (I’ve fixed the HTML entities, now generics type are correctly show) but GetMethod returns nil because GetMethod is private. This code, and the code in the SVN branch, is ONLY for Delphi XE2 Update2.

  5. Stefan Glienke Says:

    @Daniele:
    I would call it a bug in XE2. My guess is that due to the RTTI for indexed properties the getters of these properties are accessable to RTTI even if they should not because they are private. Try a dump of all methods and you see that GetItem and SetItem are the only private methods listed.

    What you are calling duck typing is no duck typing in my opinion because it requires explicit implementation of the object behind the interface you are “duck typing” to. As you said it’s kind of a dynamic adapter, nothing more.

  6. Daniele Teti Says:

    @Stefan Glienke
    I dont know if it a bug (IMHO it seems bug), but seems that setter and getter of a visibile *indexed* property are visibile too, indipendently from their own RTTI visibility.

    Also, IMHO, this is ducktyping, although, it is more an “extended” version. DuckTyping IMHO is a “way to think” not a specific implementation. The “rule” says: “If it seems a duck, it is a duck for me”. So, using an adapter or not (to change the external interface) is not a problem. However, I’m agree with you, the “extended” part (not that in the post) is more similar to a dynamic Adapter than a simply ducktyping.

  7. Stefan Glienke Says:

    FYI I made an entry into the QC: http://qc.embarcadero.com/wc/qcmain.aspx?d=100849

  8. Daniele Teti Says:

    @Stefan Glienke
    Good.

  9. Duck typing in Delphi 2007? | PHP Developer Resource Says:

    [...] Duck Typing in Delphi by Daniele Teti. [...]

Leave a Reply

You must be logged in to post a comment.

WP Theme & Icons by N.Design Studio
Entries RSS Comments RSS Log in