Interface RTTI

Posted by David Glassborow Thu, 11 May 2006 15:07:00 GMT

Reading an article and its follow up by Hallvard about RTTI inspired me to put together a couple of posts about two related areas of RTTI in Delphi. In particular one of the comments on Hallvard’s blog about using this RTTI to call objects in some late bound fashion. This post and the next cover some of the advanced RTTI that I haven’t seen covered in other places. This post covers some of the possibilities for Interface metadata, and the next one will contain details about richer class RTTI for methods.

Interface Metadata

Delphi actually has richer metadata support for methods in an Interface that in a normal class. It looks like this was added to support the SOAP features of the VCL. I’m not sure which version of Delphi it was added so your mileage may vary if your not using 2006.

IInvokable

To use SOAP, you use a WDSL file to specify the method calls, parameters, etc. If you import a WSDL in Delphi, you will notice that all Interfaces in the generated file will be derived from IInvokable. A quick peak in the System unit will show that IInvokable is:

{$M+}
  IInvokable = interface(IInterface)
  end;
{$M-}

I.e. just a standard interface, but with RTTI metadata compiled in.

Looking at the help in BDS 2006 for {$TYPEINFO ON} mentions this:

Note: The IInvokable interface defined in the System unit is declared in the {$M+} state, so any interface derived from IInvokable will have RTTI generated. The routines in the IntfInfo unit can be used to retrieved the RTTI.

IntfInfo.pas

The main procedure of interest in IntIfnfo is:

procedure GetIntfMetaData(Info: PTypeInfo; var IntfMD: TIntfMetaData; IncludeAllAncMethods: Boolean = False);

This will give us a series of records describing the methods on the interface and the parameters needed for these interfaces, as well as the unit it was defined within, the ancestor Interface and the interface’s GUID. All the names are available. both function / procedures and the names of their parameters. Calling this procedure with an interface not having RTTI will raise an exception, calling it with a class’s typeinfo will just cause an a/v :-)

When doing SOAP calls, the developer just uses the defined interface like a normal interface. Behind the scenes, Delphi packages up the parameters and sends them via a SOAP envelope to the remote server. How Delphi does this shows us some of the potential of this RTTI in Delphi, and respect for the Voodoo that is TRIO.

RIO.pas

Located in the soap folder of Delphi’s source code, RIO.pas contains the class TRIO. TRIO is an object that represents a remote object, presumably it stands for Remote Interfaced Object.

When an application casts a TRIO descendant to a registered invokable interface, it dynamically generates an in-memory method table, providing an implementation to that invokable interface.

Looking at the source for TRIO, I’ve come to the conclusion that:

MyRioObject as IMyInvokableInterface

Will cause the TRio object to

  1. Get the meta data for IMyInvokableInterface (from a registry InvRegistry object defined in InvokeRegistry.pas)
  2. Allocate memory for a vtable for the interface
  3. Allocate memory for ‘stub’ routines, marks it as containing executable code
  4. Writes machine code stubs that takes the parameters and packages them up, then calls TRIO.Generic

This is a very crude representation I knocked up in Visio:

image

When you then make a call on the ‘generated’ interface, Delphi calls the vtable, the vtables holds the address of the generated machine code. The generated machine code pushes the parameters then calls the Generic function. This packages up the parameters, and then uses a SOAP call to call the remote service. The return is then packaged up and returned in a similar way, back through the generated stub. If you are interested in how the actual machine code is generated (taking into account the 5 different calling conventions, etc.) take a look at TRIO.GenVTable function.

I don’t know which of the Delphi team wrote this code, but its very very impressive.

Anwyay I hope this has given you a feel for some of the advanced metadata available with Interfaces. The RIO approach would allow you to write Interface proxies of any Interface with metadata, for security, logging and indeed other forms of RPC remoting. Let me know if anybody suceeds in such a thing !

My followup article on class RTTI.

Posted in  | no comments | no trackbacks

Class Helpers - good or bad ?

Posted by David Glassborow Mon, 08 May 2006 15:01:00 GMT

One of the things I love about the latest versions of Delphi is the compiler changes, originally made for .Net, that are being rolled back into Win32 code. I like finally having procedures in records, and I love class helpers.

Class Helpers

Helper classes were introduced in Delphi 8 as a way of binding the VCL to the .Net framework. To quote the Delphi help: “Class helpers are a way to extend a class without using inheritance. A class helper simply introduces a wider scope for the compiler to use when resolving identifiers.”

Very simply, they allow you to add your own code to existing objects without requiring the source code or recompiling. The new code only has public access to the original object, so it cannot access private or protected data.

A simple example from my library code:

TStreamHelper = class helper for TStream
public
  function AsString: string;
  procedure WriteString( const Text: string );
  procedure WriteStringAndLineBreak( const Text: string );
end;

I got bored of writing the same code for writing a string to a stream, so I put it into a class helper, and because TStream is a base class, it works for TFileStreams, TBlobStreams, whatever.

Really a class helper is a compiler trick, behind the scenes it is just functions operating on the class, but it doesn’t polute the name space, and works with intellisense. I find myself using them more and more. The other day I was writing some code to do a gradient fill for a custom background. Very quickly the code became a helper function on the TCanvas object. Some more examples from my company’s library code:

TCanvasHelper =  class helper for TCanvas
  procedure FillGradient( Bounds: TRect; StartColour, EndColour: TColor; IsHorizontal: boolean );
end;

TListHelper = class helper for TList
  procedure FreeSelfAndContainedObjects;
end;

TDatasetHelper = class helper for TDataSet
public
  procedure InsertIntoStrings( Strings: TStrings; NameField: string; IndexField: string = '' );
  function HaveFieldsChanged: boolean;
  procedure PostIfEditing;
end;

TFieldHelper = class helper for TField
public
  function HasChanged: boolean;
end;

TTreeNodesHelper = class helper for TTreeNodes
public
  procedure ExpandToLevel( Level: integer );
  function FindOrCreateNode( NodePath: string ): TTreeNode;
end;

TRectHelper = record helper for TRect
  function ContainsPoint( Point: TPoint ): boolean;
end;

Note: the last example shows that, at least in BDS 2006, you can also write helpers for records.

Bad Design

Reading the rest of the Borland help on class helpers, you come to this statement:

Class helpers provide a way to extend a class, but they should not be viewed as a design tool to be used when developing new code. They should be used solely for their intended purpose, which is language and platform RTL binding.

I don’t agree with this, they are far more useful than just a trick for “language and platform RTL binding”

Humane Interfaces

Recently I was reading some content on Martin Fowler’s website, a site that always has an interesting perspective on software development. One of his articles that struck a cord was on “Humane vs Minimalist” interfaces.

To briefly summarise his article, he talks about the different attitude between Ruby developers, who favour rich easy to use interfaces, compared to the Java crowd who tend to favour minimal interfaces. The example he gives is of a list class and how to get the last item:

Java:

aList.get(aList.size -1)

Ruby:

anArray.last

The Ruby interface has 78 methods, the Java one 25. However the Ruby one is clearly more readable, with less visual clutter.

At Concept First our 2 overriding rules for writing code are:

  1. It should be as human readable as possible
  2. It should be as concise as possible

For this reason I favour the humane interfaces. However writing minimalist interfaces I feel leads to more concise design and less easier to test. It seems to me that class helpers give us the best of both worlds. Objects can be designed with minimal interfaces, making them quicker to develop and easier to test. We can then use class helpers to make the interfaces more humane, more readable, easier to use. The fact that class helpers can only use public methods of the object also makes sure the minimalist interface is complete.

I started off using Class Helpers to add library code to VCL objects, for library code. I now find myself using them as a design decision, putting minimalist interfaces on my objects, and adding all the helper and nicety functions as helper objects. As Marco Cantu points out, it looks like the next version of C# will support a similar feature. Personally I feel its another great feature of Delphi giving us a competitive advantage when developing with Object Pascal.

So what does everybody else think, design feature or abomination ?

Comments (originally on blogger.com)

Anonymous said…

Well, Anders Hejlsberg would seem to agree with you that they, or at least the idea of being able to extend a class, is a good thing to expose as part of the language. See http://channel9.msdn.com/Showpost.aspx?postid=114680 and http://mtaulty.com/blog/(zu0cer45karubu55u0cqsa45)/archive/2006/03/20/9271.aspx

Specificl look at Extension methods. AKA Class Helpers in Delphi.

Anonymous said…

Brilliant article

Daniel said…

Hi, David! Great article! I personally use class helpers to hide implementation details of some code on the server side of my app, while still publishing classes to the client side. Specially in our SOAP application, when we want our clients to use the same class definition as in the server. Looking forward to seeing your article about REST x SOAP…

TOndrej said…

My gut feeling is that what the help says about class helpers is correct, ie. they shouldn’t be a part of new design. For various reasons, already written classes become sealed, ie. their interface cannot be changed anymore. An ideally written class would provide all the functionality specified in the design phase, and expose enough information for descendants to extend it as new requirements come. In the real world, however, classes often hide too much or, if you like, do not expose enough. That’s where I think class helpers are a big help, they’re a way out if you’ve locked yourself in. Your argument for writing minimal classes and, at the same time, more humane class helpers seems to be based on the fact that minimal classes are easier to test and debug. I agree, but don’t you have to test and debug the class helpers, too? Isn’t the effort the same or even greater after all? Why not write, test and debug the full class right from the beginning?

The above is just my 2c; I haven’t used class helpers yet at all. Perhaps I have to play with them a bit and get a better feeling about them first. P.S. A very nice blog so far, cheers!

David Glassborow said…

Tondrej I think my point is that testing a class helper is much much easier because it can only affect the public interface, not the internals of the class. If your written the minimalist class properly, its very unlikely the class helper can break it.

TOndrej said…

OK, that’s an interesting point. I guess I’ll take a closer look at those helper beasts ;-)

Anonymous said…

The limitations seem (no private field access) seem to prevent a lot of goodies. What probably happens is that if you use type X, all imported units in the interface are searched for helperforx, since this is the only way to avoid to scan all units in the entire project for helpers to compile a unit.

Posted in  | no comments | no trackbacks

Introduction

Posted by David Glassborow Sun, 07 May 2006 14:58:00 GMT

Why Blog

Because:

  1. There are lots of technical details about delphi I’ve explored that may be useful to other developers. I’ve learnt loads from the Delphi community and I’d like to return the favour
  2. There are lots of design ‘discussions’ (i.e. arguments) i’ve had with other developers, especially my busness partner, and I’m interested in the opinions of other people on the issues
  3. To quote Paul Graham: “Expressing ideas helps to form them”

I’ve been meaning to write a blog, and host it, for a while, but haven’t got around to writing a web application to host it (although I’m still looking at doing it in RoR just to learn what all the fuss is about. So I’ve decided to host this on blogger for the moment, and maybe move it at some future point.

I’m going to write all the posts in markdown because thats the format we use internally at work, and its very easy to work with. If anybody knows any groovy tools that can markup delphi code into a web blogger friendly format, I’d really appreciate it.

In development, my prefered tool is Delphi, for lots of reasons. The greatest thing about it for me is that it comes with all the source code. My coding quality has improved more from reading the Delphi sources than anything else.

I live in the south west of England, in the UK. I live here because of the quality of life, especially being close tp the coast. In my spare time I love surfing, running, travelling, and going on expeditions to far away place like Guyana and West Papua.

Concept First

I work as a technical consultant for a small software company I started with my business partner, Dan Jones, called Concept First Ltd.

We are in our fifth year of trading, and do various types of work:

  • Business Process mapping and development
  • Web sites in ASP, Coldfusion, Websnap
  • Application development in Delphi (by choice), VB6, VB.Net, C# (by request)
  • Anything else that pays the bills !

A large number of our projects are integrating data in Enterprise environments (i.e. lots of random technologies chosen for reasons other than technical, fighting with vendors to get access to data, dispairing at money being wasted left right and centre …)

Technologies

At Concept First we like and use:

  • Delphi
  • DevExpress grids
  • Apache 2
  • Subversion
  • SQL Server (especially MSDE/Express editions)
  • Anything to do with geospatial data and mapping
  • Mind mapping software for writing specs
  • Bulleted lists ;-)

We dislike:

  • Analyists who can’t develop
  • Developers who can’t analyse
  • The new hoops you have to jump through to be a Microsoft Certified Partner company
  • Tying ourselves to Microsoft technologies
  • How bad most enterprise software is
  • How fickle the software industry is for the latest silver bullet
  • Fixed width webpages and tables for layout

Articles

I’ve got various ideas I want to write up into posts, to be done when I get time/motiviation:

  • Rich RTTI in delphi objects
  • Delphi’s class helpers, good or bad OO design ?
  • Websnap: good and bad points, how to extend it
  • Websnap and FastCGI
  • Null Object pattern in databases vs. explicit NULLs
  • Case sensitive languages and why they must be destroyed
  • Functionality vs Complexity - Time vs Money vs Quality
  • Business Logic in databases
  • REST vs SOAP
  • Tips to prevent premature optimisation

I also need to convince my business partner, Dan, to sort out a blog, coz I’m bored of him preaching to the converted.

Expect some rantings on ‘semanctic markup in html’ asap :-)

Posted in  | no comments | no trackbacks

Older posts: 1 ... 4 5 6