Skip to content

Tiburon - new language features for Delphi 2009

There are loads of new features in Tiburon for Delphi and C++Builder developers. New language features, more compatibility at the component level between Delphi and C++, C++0x draft standard language and library support, new and enhanced VCL components, and a totally revamped DataSnap.

Here is a quick look at two of the new Delphi language features - Generics and Delphi Anonymous Methods

Delphi Generics: Great for containers and collections

Declaration:

  TList<T> = class
  private
    FItems: array of T;
    FCount: Integer;
    procedure Grow(ACapacity: Integer);
    function GetItem(AIndex: Integer): T;
    procedure SetItem(AIndex: Integer; AValue: T);
  public
    procedure Add(const AItem: T);
    procedure AddRange(const AItems: array of T);
    procedure RemoveAt(AIndex: Integer);
    procedure Clear;
    property Item[AIndex: Integer]: T
      read GetItem write SetItem; default;
    property Count: Integer read FCount;
  end;

Use:

var
  ilist: TList<Integer>;
  slist: TList<String>;     

procedure PrintListInteger;
var
  i: Integer;
begin
  for i := 0 to ilist.Count - 1 do
    Write(ilist[i], ' ');
  Writeln;
end;         

procedure PrintListString;
var
  i: Integer;
begin
  for i := 0 to slist.Count - 1 do
    Write(slist[i], ' ');
  Writeln;
end;         

begin
  ilist := TList.Create;
  try
    ilist.AddRange([1, 2, 3]); // ['1', 'second', 'third']);
    PrintListInteger;
    ilist.RemoveAt(1);
    PrintListInteger;
    ilist.Clear;
    PrintListInteger;
  finally
    ilist.Free;
  end;
  slist := TList.Create;
  try
    slist.AddRange(['one', 'two', 'three']); // ['first', 'second', 'third']);
    PrintListString;
    slist.RemoveAt(1);
    PrintListString;
    slist.Clear;
    PrintListString;
  finally
    slist.Free;
  end;
  Readln;
end.

The Tiburon Generics.Collections unit includes: TList, TQueue, TStack, TDictionary, TObjectList, TObjectQueue, TObjectStack, and TObjectDictionary.

Delphi Anonymous Methods: use them when nothing else is nearly as good, ideal for passing code when you need to parameterize types and procedures by code or behaviour. You can also "simulate" new syntax constructs defined entirely in libraries. Don’t use them when for/in or an equivalent loop would do.

Declaration:

type
  // method reference
  TProc = reference to procedure(x: Integer);               

procedure Call(const proc: TProc);
begin
  proc(42);
end;

Use:

var
  proc: TProc;
begin
  // anonymous method
  proc := procedure(a: Integer)
  begin
    Writeln(a);
  end;               

  Call(proc);
  readln
end.

For a look at the new language construct for Exit, check out Nick Hodges blog at http://blogs.codegear.com/nickhodges/2008/07/22/39079/

{ 25 } Comments

  1. Maël Hörz | July 23, 2008 at 5:42 pm | Permalink

    Somehow the parametrization of TList seems to be missing: I see the use of T, but nowhere , such as in TList.

  2. Maël Hörz | July 23, 2008 at 5:46 pm | Permalink

    Ok. I see, the blog system eats angular brackets.

    Reformulated previous post:

    Somehow the parametrization of TList seems to be missing: I see the use of T, but nowhere (angular bracket open) T (angular bracket close), such as in TList(angular bracket open)T(angular bracket close).

  3. Richard Foersom | July 23, 2008 at 6:21 pm | Permalink

    Generics - Great! Finally!

    Anonymous methods - I have not yet understood why this should be so important. AFAI can see the same thing can be achieved by pointer to a function.

  4. Barry Kelly | July 23, 2008 at 6:31 pm | Permalink

    @Richard - anonymous methods can capture local variables and store them; they are then available to that method for as long as a reference to it exists.

    This is important if you want to e.g. run some code on a different thread (perhaps a background thread, or the UI thread); you’ll probably want to not only pass a function (for which a function pointer would do), you’ll probably also want to pass some state, i.e. the data to work with in the other thread.

    Because anonymous methods capture variables from their context, just referencing the data means that it is available in the other thread, when the code of the anonymous method is running.

  5. Edwin Yip | Mind Mapping Innovation | July 23, 2008 at 6:45 pm | Permalink

    Thanks Barry’s explanation, now I have a clue on what the purpose of the anonymous methods is.

  6. Jolyon Smith | July 23, 2008 at 7:51 pm | Permalink

    OK, and on the face of it a perfect demonstration of why generics are a great demo for trivial examples which hide an intrinsic problem that is made harder to identify and resolve.

    Given the TList implementation in the example, what exactly will happen if I declare a olist := TList? A call to WriteLn(olist.Items[i]) is going to do what?

    In this case, not compile, because the offending method is in code external to the generic. But what if I have some code in the generic implementation itself that does this? i.e. makes some call that requires particular characteristics to be met by the specific T used to instantiate the generic.

    At the very least this raises the need for a constraints specification - does this exist in the Delphi implementation? What does it look like?

    Then of course, those constraints themselves introduce some interesting challenges for consumers of your generics. In the absence of entirely bulletproof constraints you need to scour the source of the generic to ensure that the specific type T you intend to use is actually supported by the generic implementation (something that a polymorphic approach ensures - your base class can only be written in terms of the base types it supports. It is not working with an arbitrary and unspecified type that may or may not be compatible when actually resolved to a specific type).

    And in the presence of entirely bulletproof constraints, your "generic" is no longer truly generic anyway.

    The ONLY argument FOR generics I have heard (apart from the "gosh darn it, they are so sexy and cool " one) is that they "save a huge amount of time".

    Where "huge" is unspecified and, when pressed to quantify, is eventually acknowledged as actually trivially small in comparison to the eventual lifetime and overall development effort of the code in question.

    But they’re sooooo sexy.

    Which for some reason reminds me of that classic line: Gentlemen may prefer blondes but they MARRY brunettes.

    Sexy is fun, but it’s no basis [on it's own] for a stable, long term relationship.

    @Barry - w.r.t variable "capture"….. isn’t that [one of the reasons] why a thread in Delphi has always been represented by a class? You can pass state to the thread via the member variables of the thread. Even better of course, the thread can pass [basic] information back the same way.

    And [problems with TThread itself aside] that’s a darn sight easier to understand when reading the code back weeks/months/years later.

    The example provided is actually cleaner and no different if implemented using a straightforward procedure type, as Delphi has had from the get go but which C# didn’t have and which - in the specific exemplar case - is just as good but also easier to read and understand.

    In C# anonymous methods tidy things up - a little. In Delphi, they introduce a great deal of source complexity for very, very little benefit (unless you have as a goal an arbitrary compatability or "marketting comparability" with some other language, as opposed to having features designed to actually add something of intrinsic value to the language they are being added to).

  7. Sebastian P.R. Gingt | July 23, 2008 at 10:06 pm | Permalink

    >> The ONLY argument FOR generics I have heard
    >> is that they "save a huge amount of time".

    Not only time. The point is, that they enable you to re-use your tested quality-code on many occasions you could not use it by now.

    That will prevent you from copy & pasting & changing your List1-Code to support List2 (and possibly introducing bugs while doing that). And if you want to put another feature in your ~50 units that contains your lists, you only have to write it once and not 50 times (or copy & waste & introduce bugs while doing that).

  8. Onno | July 23, 2008 at 10:55 pm | Permalink

    I’ve been longing for generics support in Delphi for a *long* time… This is so cool! I really appreciate the renewed efforts you guys are putting into Delphi :)

  9. Nicholas Brooks | July 23, 2008 at 10:56 pm | Permalink

    Good stuff! Though David I think you are doing yourself and the CodeGear developers a disservice by using such a trivial example for anonymous methods.

  10. Steffen | July 23, 2008 at 11:52 pm | Permalink

    Will the above generics example work using a record structure for T?

  11. Kryvich | July 24, 2008 at 12:08 am | Permalink

    David, I’m confused, why you didn’t use the for-in loop? Is it possible with Delphi’s generic collections:

    procedure PrintListInteger;
    var
    elem: Integer;
    begin
    for elem in ilist do
    Write(i, ‘ ‘);
    Writeln;
    end;

  12. Andreas Hausladen | July 24, 2008 at 2:18 am | Permalink

    @Kryvich: Maybe he want fast code and not the for-in slowdown by allocating the enumerator object, calling MoveNext, GetCurrent and then releasing the object.

  13. Kryvich | July 24, 2008 at 2:37 am | Permalink

    Andreas Hausladen -

    OK, I agree with you. I’ve just asked about possibility.

  14. Markus | July 24, 2008 at 2:57 am | Permalink

    Hi,

    I am completely new to generic types - so I have some questions about it:

    -> In your example, T can be a string or an integer. Is it possible to write things like these in the above example? (think of normal brackets as angular ones)

    var
    olist: TList(TObject);
    rlist: TList(TMyRecord);

    ->if such a data type also can be a TObject, things like a base class for it, e.g.:
    (think of normal brackets as angular ones)

    TMyClassWithGenericParameter(T:TComponent) = class

    end;

    …would be interesting - will this be possible?

  15. Andrey | July 24, 2008 at 4:31 am | Permalink

    The anonymous method example demonstrate nothing. It is not inline in Call. It does not capture any local variables into context. The word "closure" in never used in the post. So, what is actually the anonymous method?

  16. Andrey | July 24, 2008 at 4:48 am | Permalink

    The generics example is so basic that it is almost useless. Are Delphi generics like Java? Or like C#? Or like C++? Generics are a well known concept already and it is also well known that "small" implementation differences are critical. What kind of generics will be in Delphi Win32 2009?

  17. Ricardo Cardona R | July 24, 2008 at 5:39 am | Permalink

    where is screenshots for the ribbon control ?
    thanks

  18. Jolyon Smith | July 24, 2008 at 1:12 pm | Permalink

    @Sebastian

    "The point is, that they enable you to re-use your tested quality-code on many occasions you could not use it by now."

    No, that isn’t the point at all. The ONLY point is that they enable lazy people to create type-safe containers (lazy people specifically because there’s nothing to stop someone creating type safe containers WITHOUT generics, as long as they are prepared to put the effort in - a very small effort at that).

    The argument for generics rests on an assumption that people can’t be bothered to spend the few minutes it takes to roll type safe derivatives of base polymorphic containers and so are using unsafe, untyped containers.

    THAT’s the danger it prevents and the time it "saves".

    If you aren’t rolling type safe containers then generics give you an lazy way to do what you weren’t doing before, so you don’t save any time anyway (because you weren’t investing that time in the first place).

    If on the other hand you are already rolling type safe containers then you will know that the time that generics will save you is vanishingly small in the grand scheme of things and the additional problems and constraints that they introduce will more than likely offset any gains you may make over the life of a project.

    You will also know that in many cases your TList will actually have some very specific behaviours for many of the specific ’s that you wish to use, something that a TList cannot always gracefully accommodate.

    e.g. I want a TList that will only allow items to be Add’ed, not Remove’ed, or which when "Add’ing" does something other than JUST plonk it in the list.

    When designing a TCustomerList you get to think about and make all the appropriate design decisions. It takes longer but you get a better fitting piece of software at the end of it.

    When declaring a TList you get a nice quick result that hasn’t required any thought…. something which you will likely pay for WAY down the track (the cost of which is notoriously hard to measure vs the very easily measured time "saved" in creating the misbegotten class in the first place, hence the very natural appeal of generics).

    Of course, I may be wrong. Generics apparent benefits may be not only seemingly obvious but also well proven…. since we are told that they are well established and that Delphi is behind the curve on this, there may be a wealth of metrics and case studies that prove beyond any doubt that the benefits that people THINK they will bring are concrete and easily realised.

    Funny thing though, in all my debates on the matter, no-one has EVER managed to provide any references to any such material.

    Similarly:

    If you are already rolling type safe containers then you are already able to reliably re-use well tested code.

    If you are not rolling type safe containers then you are ALSO reliably re-using well tested code, but your NEW code (consuming the unsafe types) will need to be tested to ensure that it is using that tested code correctly.

    But correct me if I’m wrong, but if it’s new code then it needs testing anyway.

    Unless you are formulating an argument for "Testing by assumption"….

    It wouldn’t surprise me in the slightest - generics are very appealing to a lazy software development mindset, as would be a Testing By Assumption methodology.

  19. Maël Hörz | July 24, 2008 at 1:42 pm | Permalink

    @Jolyon Smith:
    Not going to answer to all the points you made directly, instead I’m going to mention some general things.

    - You can have a generic list and testing it well. The substitute the type and it you don’t need further testing (if it wouldn’t work you would get compile errors).

    - Code-duplication is bad, as things can get out of sync, and you need to test more. That is pretty much the same thought as using classes and inheritance.

    - Being lazy in the sense of having less duplication and simpler code is good, since in general simpler system are less error prone.

    - You can still write your own list tailored to a specific need and write you own accessor methods that only give the access that is necessary and hide everything else. Internally you could still use a TList.

    - Arrays are also a kind of generic type. You can have arrays of int, char, boolean, string, … All are accessible through the same interface: Indexing a[i], Growing/Shrinking SetLength(), etc.

    - Generics aren’t bad at all, as most things it depends on the way it is used. Similarly it is also a bad idea to make an array accessible directly without proper accessors methods. That doesn’t mean arrays are bad in general.+

    - You start on a low-level of abstraction and then put higher layer on top of it. It is rarely a good idea to directly expose the interface of the data-structure you use.

  20. Maël Hörz | July 24, 2008 at 1:45 pm | Permalink

    Reformulated first point:
    - You can have a generic list which is well tested. Then substitute the type and you don’t need further testing (if it wouldn’t work you would get compile errors).

  21. El Cy | July 24, 2008 at 10:28 pm | Permalink

    Why this construct is named anonymous "method" … since all the demos so far shows anonymous "functions" or "procedures" …. A method related to an object instance … so there si also a real anomymous "method" construct like the one below supported ?

    type
    // object method reference
    TObjectProc = reference to procedure(x: Integer) of object;

    How about a a "class" anoymous method … see bellow ?

    type
    // class method reference
    TClassProc = reference to class procedure(x: Integer);

    Just wondering ….

  22. El Cy | July 24, 2008 at 10:36 pm | Permalink

    Regarding the generic types in win32: Are all the features available in Delphi.NET also supported in Delphi.Win32 ?

    Ex:
    - generic type constraints (constructor, base type, interface … etc)
    - Default(T)
    - Nullable types
    … etc

    Those interested can find here a very nice video presentation on generics/parametrized types (available in Delphi.NET) by Allen Bauer : http://video.codegear.com/RADStudioDevDaysSep2007/Generics/paramtypes.html

  23. DelphiUser | July 25, 2008 at 2:58 am | Permalink

    Phrases like "Syntactic Sugar" and "Lazy Programming" are meaningless. My clients don’t pay me to program the hard way. Anything that gets the job done faster whilst remaining easy to maintain makes for a desirable programming tool. Else we’d still be using assembler.

    Generics, as implemented in C#, were a revelation to me. Easy to use, well-integrated with Microsoft’s Intellisense (very, very important! Intellisense knows the type) and easy to see later what it’s doing because it needs less "glue" code.

    Long discussions won’t convince anyone. But once you’ve used them, you’ll never want to work without them. C#’s Dictionary class is brilliant.

    Only remains to be seen whether our Delphi guys did with C# generics the same that Anders H did with Delphi for C#: Pick out the best bits and improve the weaknesses that have revealed themselves over time.

  24. Jeff C. | July 25, 2008 at 11:34 am | Permalink

    The three commonly used collection classes in .NET are ArrayList, Hashtable and SortedList. What will be the equivalents in the Tiburon Collection classes and will they provide all the functionality and common methods that .net programmers have at their disposal? Do we have iterators and comparators?

    Also what about the specialized Collection classes that are in .NET such as:

    StringCollection
    StringDictionary
    ListDictionary
    HybridDictionary
    SortedList
    SortedDictionary
    OrderedDictionary

    NOTE: In .Net, the Hashtable and SortedList classes manage a collection of key-value pairs. The difference between the Hashtable and SortedList class is that in the SortedList class, the values are sorted by keys and are accessible by key as well as by index.

    I just hope the new collections in Tiburon cover at least the breadth of what most modern framework collections provide, since this has always been lacking in the out of box Delphi language.

    I would think these announcements are just a peek into whats coming, so I am looking forward to hearing more about the new collections and generics as Tiburon nears release.

    SUGGESTIONS:

    Having sonething like this in the Tiburon documentation would also help new developers using these collections:
    http://msdn.microsoft.com/en-us/library/6tc79sx1(VS.80).aspx

    Also would be great if you created a sub project like this in which the community could maintain a more specialized version of collection classes. Rather than having versions popup all over the net:
    http://www.codeplex.com/PowerCollections

    IN COMPARISON:

    Java Collections:
    http://java.sun.com/j2se/1.5.0/docs/guide/collections/reference.html

    Not to mention the additions the Apache project made:
    http://jakarta.apache.org/commons/collections/

    And .NET:

    System.Collections:
    ArrayList
    Hashtable
    CollectionBase
    Stack
    Queue
    BitArray

    System.Collections.Specialized:
    StringCollection
    StringDictionary
    ListDictionary
    HybridDictionary
    SortedList
    SortedDictionary
    OrderedDictionary

    Announced for Tiburon:

    "The Tiburon Generics.Collections unit includes: TList, TQueue, TStack, TDictionary, TObjectList, TObjectQueue, TObjectStack, and TObjectDictionary."

  25. fdbsh | August 19, 2008 at 9:49 pm | Permalink

    期待

Bad Behavior has blocked 4 access attempts in the last 7 days.

Close