RTTI and Attributes in Delphi 2010

RTTI (Runtime Type Information) has had a major overhaul in Delphi 2010. RTTI is a central piece on which the Delphi IDE is written, and as such has been around since the first release, however I’ve heard from a number of people over the years that they’d tried to use RTTI and found it too difficult and arcane, especially compared to the Reflection API’s in Java and .NET. That’s a real shame, as the ability to write code to query the details of other objects, without knowing the type up-front, is really powerful.

However, I think that complaint will be a thing of the past with this new API. It’s been not only extended to make it more capable, it is also now much more approachable and easy to use.

One of the new features that I’m very excited about is support for Attributes in Win32. I’m working on a larger example, but here’s a quick run through of creating and then querying custom attributes.

Custom attributes are simply classes that descend from TCustomAttribute. They can have properties, methods, etc, like any other class:

  MyAttribute = class(TCustomAttribute)
  private
    FName: string;
    FAge: Integer;
  public
    constructor Create(const Name : string; Age : Integer);
    property Name : string read FName write FName;
    property Age : Integer read FAge write FAge;
  end;

No real surprises here, and the constructor is implemented exactly as you’d expect.

Next, we can apply our attribute to our class:

  TMyClass = class
  public
    [MyAttribute('Malcolm', 39)]
    procedure MyProc(const s : string);
    [MyAttribute('Julie', 37)]
    procedure MyOtherProc;
  end;

Here I’ve applied it to both methods, but note I’ve supplied different parameters to the Attribute. Also note the order of the parameters matches the order in the constructor. This is not just limited to methods, you can apply attributes to properties, entire classes, all sorts of things.

Of course, there’s no point adding attributes if you can’t read them from somewhere, so here’s some sample code that uses the new RTTI API to query for our attributes, and display the details in a listbox:

procedure TForm3.Button1Click(Sender: TObject);
var
  ctx : TRttiContext;
  t : TRttiType;
  m : TRttiMethod;
  a : TCustomAttribute;
begin
  ListBox1.Clear;

  ctx := TRttiContext.Create;
  try
    t := ctx.GetType(TMyClass);
    for m in t.GetMethods do
      for a in m.GetAttributes do
        if a is MyAttribute then
          ListBox1.Items.Add(Format('Method = %s; Attribute = %s, Name = %s, Age = %d',
                                    [m.Name, a.ClassName, MyAttribute(a).Name,
                                     MyAttribute(a).Age]));
  finally
    ctx.Free;
  end;
end;

First I grab a reference to the RTTI Context, and load it with the ClassType of my class. I then do a for..in over the methods in my class, and for each method do a for..in over the attributes. Then I check if the attribute is my custom attribute, and if so, grab the values of Name and Age and show them in a list box.

attribscreenshot

As I mentioned earlier, I’m working on another example which is a little more useful, but hopefully this gives you a little taste of some of the new stuff coming in 2010. Also, don’t forget to watch the preview videos at http://www.embarcadero.com/rad-studio-2010/, and subscribe to get notified when new ones are published.

42 Comments

  • Twitter Comment


    RTTI and Attributes in Delphi 2010 [link to post]

    Posted using Chat Catcher

  • Twitter Comment


    RT @malcolmgroves: RTTI and Attributes in Delphi 2010 [link to post] | A Short post with a lot of information in it!

    Posted using Chat Catcher

  • I hope your next example gives me a clue as to why you’d want to do such a thing 😉

  • 🙂 Sure, I’ll do my best. That said, there are plenty of interesting examples of attribute usage in the .NET and Java world. A little googling should reward your curiosity.

  • Twitter Comment


    r @malcolmgroves: RTTI and Attributes in Delphi 2010 [link to post] geek drool. This will be so useful.

    Posted using Chat Catcher

  • […] first, let us try to calm the stir provoked by a post of Embarcadero’s Malcolm Groves in which our Senior Director talks a little bit about […]

  • Three questions:

    1. So there’s no naming convention for attributes? Delphi won’t have the nice “attribute class names typically end with ‘Attribute’, which you can leave off when you’re applying the attribute” syntactic sugar?
    2. How expensive is creating an RTTIContext? Does it load and parse all the RTTI in the app (and therefore take a long time to instantiate, but giving you faster lookup), or does it just give you a shell you can work with (and can be created cheaply)?
    3. Is there something like .NET’s AttributeUsage, where you can say things like “this attribute can only be applied to classes”?

  • Does this new API work on interfaces as well? It would be _very_ useful.

  • Joe:

    1) Not correct. You can leave out the Attribute portion and it works fine. I’ve just confirmed this my using the name of My in my example, and it still picked it up as MyAttribute.
    2) No idea. Good question for Barry Kelly.
    3) I believe so, and it’s on my draft to include in the next Attribute post later this week that has a more useful example than the one used here. This was just meant as a quick intro.

  • Marton : Not sure. I’ll add it to my list of things to check. I haven’t tried RTTI on interfaces at all, to be honest.

  • I can’t see the point. To me it looks like, “We can be as woolly and sloppy as some other language.” Delphi (Pascal) should be like Switzerland, a brilliant country that nobody can mess with and that does its own thing perfectly. I wish they wouldn’t try to turn it into Brazil.

  • For member specific attributes I see there’s no way to avoid introducing the noise of an attribute declaration using this approach.

    For attributes that apply to a BLOCK of members, is there any way to avoid unnecessarily duplicating the attribute declaration?

    Perhaps an extension to the visibility specifier:

    private([BrowsableAttribute()])
    fName: String;
    fAge: Integer;

    To “tag” the members fName and fAge with the BrowsableAttribute(), as opposed to:

    private
    [BrowsableAttribute()]
    fName: String;
    [BrowsableAttribute()]
    fAge: Integer;

    In a similar vein, how about a compiler directive to allow us to externalise these things:

    {$attributes ‘customer.attr’}

    TCustomer = class
    private
    fName: String;
    fAge: Integer;
    end;

    where customer.attr is a file containing the attribute declarations (typically modelling an implementation detail) that would otherwise get in the way of the code modelling the business concern, e.g.:

    attributes
    TCustomer: [TableName(‘CUSTOMER’)];
    TCustomer.fName: [FieldName(‘CUST_NAME’); RequiredField()];
    TCustomer.fAge: [FieldName(‘CUST_AGE’)];

  • […] baffles off the old system.  One nice thing that falls out from that is [Attributes].  Malcolm Groves has the goods, with a promise of more to […]

  • […] News on new features in the next version of Delphi keeps coming in. So far nothing really exciting has been announced, until Delphi on Win32 gets Attributes. […]

  • Ossian : Err, OK. I’m not very familiar with either Switzerland or Brazil.

    Jolyon : Interesting ideas, but my concern would be that you might make it a little less obvious which attributes are attached where, especially with the external file one. I guess it will remain to be seen how many attributes people end up using in a single class as to how unwieldy it’ll get. At the moment I can imagine all sorts of usages, but time will tell how many I actually use long term. I CAN see that too much may not necessarily be a good thing.

  • People keep asking why you’d want to use attributes. The most obvious answer, to me at least, is serialization. With the new RTTI, you could almost completely automate serialization, but a lot of objects relate to other objects in interesting and unusual ways that would make it difficult to write generalized rules for. You could use attributes to deal with these special cases.

  • Very, very interesting, Malcolm.

    Only a small detail:

    ctx.GetType(MyClass.ClassType)

    I believe that it should be:

    ctx.GetType(TMyClass.ClassType)

    Thanks.

    Al Gonzalez. 🙂

  • Twitter Comment


    Delphi2010いいなー [link to post]

    Posted using Chat Catcher

  • Thanks for the informative blog posts Malcolm. Some questions:

    So you don’t have to include the Attribute suffix when applying the attribute. Do you have to include the T prefix (if the attribute class name includes it)? Being able to configure prefixes to ignore would be nice (a pipe dream). e.g. TtiUndoableAttribute (ti is for tiOPF) can be specified as [Undoable].

    You mentioned that you can have attributes on classes, methods, properties and “all sorts of things”. Can they be applied to fields (variables not defined through a property)?

    Can you have multiple attributes for a given class/method/field/property? e.g.

    TMyClass = class
    public
    [MyAttribute(‘Julie’, 37)]
    [MyOtherAttribute]
    procedure MyOtherProc;
    end;

    That looks to be possible from your example “for a in m.GetAttributes do”.

    Can you have attributes on virtual methods? e.g.

    TMyClass = class
    public
    [MyAttribute(‘Julie’, 37)]
    procedure MyOtherProc; virtual;
    end;

    TMyOtherClass = class(TMyClass)
    public
    [MyAttribute(‘John’, 29)]
    procedure MyOtherProc; override;
    end;

    If so then which attributes apply to TMyOtherClass.MyOtherProc? One or two MyAttributes?

    In your example you use: “t := ctx.GetType(MyClass.ClassType);” (I’m assuming MyClass is an instance of TMyClass), ie query attributes by class. Could you simply have written: “t := ctx.GetType(TMyClass);” or is an instance required and some magic going on?

    I’m asking because some design discussion on tiOPF we’ve been having in the last few days could benefit from the use of attributes (persistence, memento pattern).

    Thanks for any additional information that you can provide.

    Cheers,
    Jarrod Hollingworth

  • Al : Actually, MyClass is correct. It’s an instance of TMyClass (the confusing part if I didn’t show that int he source snippets above, sorry). ClassType is not actually a class method, as it references Self, so TMyClass.ClassType would not work.

  • Jolyon : One other thing that might be problematic with your “block attributes” idea, is handling multiple attributes on a single item. Not that that negates the idea, just an extra complication.

  • Hi Jarrod,

    1) You don’t have to include the Attribute suffix (if there is one) but you do need the rest, including any prefix.
    2)I’ll post something on the full list of things you can add attributes in my coming example (I showed the code off in Melbourne yesterday, but have to finsih the write-up). Fields work. There is a TRTTIField type and a GetFields method to return the collection.
    3) Multiple attributes for a single item : Yes, definitely.
    4) Attributes on methods you override. Yep, and in your example the descendant class will have two attributes.
    5) MyClass.GetType vs TMyClass : yep, they both seem to have the same end result. I had an instance floating around, so I used that, but just passing in the type itself is even more clear. I think I’ll adjust the example. Thanks.

    Cheers
    Malcolm

  • […] my previous post on Attributes in Delphi 2010, I showed a basic view of the mechanics involved in creating, applying and querying Attributes. I […]

  • Is there support for named parameters in the attributes like in .NET for example:

    [MyAttribute(Name = ‘Julie’, Age = 37)]

    I would really miss that one if not supported.

  • […] у WoW, после чего досконально изучаем посты Malcolm Groves тут и […]

  • […] and subscribe to get notified when new ones are published.来源:http://www.malcolmgroves.com/blog/?p=476 Categories: Delphi Tags: Delphi 2010, RTTIEmbarcadero.RAD.Studio.2010_V14.0.3513.24210 Comments […]

  • […] 08-3-19 */ google_ad_slot = “7395205248”; google_ad_width = 468; google_ad_height = 60; In my previous post on Attributes in Delphi 2010, I showed a basic view of the mechanics involved in creating, applying and querying Attributes. I […]

  • […] example is around Refactoring support for Attributes. If you look at my first, simple example of Attributes, one of the many things wrong with it is that the Attribute name is terrible. Unless I never plan […]

  • Twitter Comment


    정적타입체크를 중시하는 C++의 경우 아직 RTTI의 사용이 많지않죠. 델파이는 어떨까요? RT @programmingjoy: RTTI and Attributes in Delphi 2010 #programming [link to post]

    Posted using Chat Catcher

  • […] Malcolm Groves | RTTI and Attributes in Delphi 2010 http://www.malcolmgroves.com/blog/?p=476 – view page – cached By Malcolm ⋅ August 15, 2009 ⋅ Email This Post Email This Post ⋅ Print This Post Print This Post ⋅ Post a comment Filed Under Attributes, Delphi, Embarcadero, RTTI — From the page […]

  • Twitter Comment


    RT @programmingjoy: RTTI and Attributes in Delphi 2010 #programming [link to post] (Does anyone use Delphi anymore? I mean, it’s dead!)

    Posted using Chat Catcher

  • Twitter Comment


    RTTI and Attributes in Delphi 2010 #programming [link to post]

    Posted using Chat Catcher

  • The most obvious answer, to me at least, is serialization. With the new RTTI, you could almost completely automate serialization, but a lot of objects relate to other objects in interesting and unusual ways that would make it difficult to write generalized rules for.

  • Yes, that’s usually the example given. If you look at my follow-up article on attributes (http://www.malcolmgroves.com/blog/?p=530), you’ll see a link to an example of that.

  • […] Example explanation of Attributes in Delphi: http://www.malcolmgroves.com/blog/?p=476 […]

  • […] Malcolm Groves » RTTI and Attributes in Delphi 2010Aug 15, 2009 … RTTI (Runtime Type Information) has had a major overhaul in Delphi 2010. RTTI is a central piece on which the Delphi IDE is written, and as … […]

  • […] welcome new language feature in Delphi 2010 is the introduction of attributes, as previously found in .NET languages.  However I am slightly disappointed that the language […]

  • […] […]

  • […] heard a lot about the new/improved RTTI capabilities of Delphi 2010, but I must admit my ignorance…I don’t understand it. I know every version of Delphi […]

  • […] you have it — a “real” use case for attributes in Delphi. The key advantages I see to this approach, as opposed to, say […]

  • This is a somewhat delayed response, but we’ve found a good use for attributes in documenting and testing thread safety: http://marc.durdin.net/2014/05/using-delphi-attributes-to-unify-source-test-and-documentation/

Leave a Reply to Nick Hodges » Blog Archive » Random Thoughts on the Passing Scene #119 Cancel reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>