Class Helpers - good or bad ?

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 by David Glassborow Mon, 08 May 2006 15:01:00 GMT


Introduction

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 by David Glassborow Sun, 07 May 2006 14:58:00 GMT


Older posts: 1 2