[Estimated Reading Time: 4 minutes]

NEWSFLASH: I believe I have found a use for class helpers in the wild!

This, even though I have long held the view that class helpers should not be viewed as a general purpose utility. They were designed for a very specific purpose and the authors of the technology themselves tell us how they are intended to be used. Using them in other ways is asking for trouble: they can break your – or others – code, they hide details of an implementation in A Bad Wayβ„’ and you are likely to run into limitations because what you want to use them for doesn’t tally with what they are intended to be used for.

But, somewhat to my surprise, I have recently found what I consider to be a legitimate use for them. Less surprisingly, it actually fits with their intended use.

First, The Context

I am currently implementing a client/server system. Not an SQL client/server, but a REST client server. That is, a Delphi application server which exposes services to a Delphi GUI client using REST to invoke those services and JSON to transport object representations between client and server.

I have classes that are used in both client and server contexts. For example, I have a class representing a property list – a list of named and typed values.

A client receives a property list in response to some request to the server in the form of a JSON array, and also it sends propertly lists to the server as part of a request. Obviously the ability for a property list to serialise to/from JSON is necessary in both client and server contexts for this class, and so it is an intrinsic behaviour to that class.

However, the client has other things that it is useful to do with an instance of that class.

For example, when updating a form in the GUI, it will wish to apply string values from a property list to edit controls, booleans to check-boxes/radio buttons, enum value to combo-boxes.. etc etc.

Clearly, putting methods to assist with these behaviour on the class is inappropriate since in the server context such methods have no use what-so-ever and would only pollute the interface on the class.

But having a client-side specific sub-class is also over-kill. I do not want to have remember that when coding in the GUI I use the TClientPropertyList rather than TPropertyList. Equally I do not really want to have to invoke cumbersome first-class procedures such as SetCheckboxFromProperty( propList, checkbox ) when the more intuitive propList.SetCheckbox( checkbox ) could be made available.

Class helpers actually have a role here, and it fits the original vision perfectly.

A Class To Help – A Class Helper

Let us briefly revisit the vision for class helpers, in the form of the documentation:

You can use the class helper any place where you can legally use the extended class. The compiler’s resolution scope then becomes the original class, plus the class helper.

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.

One thing to be wary of is the directive w.r.t using them as a design tool for new code, but in my case I believe that the fact that I am employing the helper to assist with “platform RTL binding” overrides this concern. I am creating a platform – my application architecture – and what I am doing by employing a class helper in this case, is extending a class in a particular, and unambiguous, context within that platform.

That is, I am creating an extension for a class which is relevant only to client code on my platform.

Furthermore, I “own” both the original class and the context in which it is being used. There is no risk here that my helper will break or otherwise interfere with another helper for the same class. If I ever need to embellish the original class, I will simply do so, and ensure that the client-context helper provided by the platform is updated accordingly, if necessary.

The Resulting Architecture

What I ended up with was 2 units:

   Project.PropertyList;   // Contains the TPropertyList itself
   Project.Client.Utils;     // Contains the client-side TPropertyListHelper among other things

The server project obviously doesn’t employ any of the Project.Client.* units. The client projects employ both the property list but then also use the client specific Utils unit if/when required.

When I am coding up the GUI for my project in the client, I add Project.Client.Utils to my uses list and my TPropertyList instances are now endowed with GUI/client specific methods to help get/set values from GUI controls. If my client code is not actually concerned with GUI aspects, then it simply works with TPropertyList as-is, without even bringing the helper into scope if not required.

When I am coding up the server-side code, I simply work with TPropertyList itself.

And if I ever need any server-side specific extensions to the class (for example, adding methods to persist a propertly list in an SQL database on the server-side), I could introduce a server-side helper into Project.Server.Utils.

So there is a valid use for class helpers, but I still maintain that using a class helper to extend/embellish classes from *other* libraries/frameworks is A Bad Ideaβ„’, because you potentially won’t be the only person with an idea of what makes a good extension/embellishment to that class. As soon as you share code with someone who has different ideas, one or other of you is going to have to change their ideas and, potentially, a great deal of code.

6 thoughts on “Class Helpers: Extending Classes for Context”

  1. Thanks for this great example on how class-, or rather type-helpers can be put to good use.

    However, personally I consider it complete & utter nonsense to limit this otherwise great language feature – what if you not only wanted to add GUI-interaction to your TPropertyList, but also want to add filtering and/or ordering features – or anything else that has it’s place in some occasions?

    Except for some potential symbol-name conflicts (which are easy to avoid), I don’t see why we’re being hindered in using multiple helpers.
    I mean – with type helpers we finally have an ‘OO flavoured’ solution for separating additional logic into a few neath little ‘aspects’ so to speak, and then they allow only one extension!

    Surely, one can get around it, by explicit helper-type references (which defeats the point), casts to subclasses (some problem), or by going procedural again (with methods in the form “TPropertyList_DoSomething(Self: TPropertyList; Arguments: type)”) which isn’t really OO anymore.

    I just don’t get it – it feels like a step in the right direction, but on a leach… and why? I haven’t seen a real good reason. Perhaps it is because type helpers where made as a means-to-an-end, without any real commitment towards them. (Surely, it has nothing to do with any added complexity in the compiler.)
    But the cat’s out of the bag already, and people would like to use this language feature in their designs… except we can only do it once (and I’m not alone in this feeling : see http://davidglassborow.blogspot.com/2006/05/class-helpers-good-or-bad.html for example.)

    Okay, I’ll get off my soapbox now. Thanks for listening, and sorry for the hijacking of your otherwise good writeup πŸ˜‰

  2. No worries Patrick. All comments welcome, hijacking or otherwise. πŸ™‚

    In my view it all comes back to the same point: class helpers were not and are not designed for general purpose use – it say so right there in the documentation!

    The problem is that people ignore that guidance and then complain that helpers are too limited. But they aren’t limited for what they were originally designed for.

    Would we like a more comprehensive language feature in this area? Perhaps, though I remain skeptical of the validity of obfuscating things for the purpose of simplifying code creation which then have to be de-obfuscated during the far more significant period during the lifetime of the code as it is maintained and extended.

    Incidentally, imho class helpers really aren’t OO themselves – they merely facilitate syntactic sugar which maintains an illusion of OO’ness.

  3. Hi, thanks for good article!

    But did you knew that you can write more than one helper for one class? I’m talking about problem with third-party helpers and possible conflicts. I created some demo code here https://gist.github.com/4e23b7fa71717aa6f052 (its to big for comment, so I had to use external site).

    It uses inheritance of class helpers – I think its good idea, because compiler can’t (and shouldn’t) decide which helper has bigger priority. So you, as a programmer, have to explicitly tell it. If you don’t want to add external dependency for users of your helper, you could use {$IFDEF}s

  4. @Frantic – Yes I am aware you can have multiple class helpers for the same class.

    I’m not entirely sure what your point is tho… are you saying that there are ways around the issue of helper collisions by using inheritance? If so, then that works as long you have only 2 helpers in collision, and as long as you are happy to derive your helper from the other, in order to “merge” them (and assuming that it makes sense to do so where the two helpers have methods with names that also collide).

    But this quickly get’s messy and falls apart completely if you then find another helper getting in the way.

    “Class Helpers” in such scenarios quickly become “Code Comprehension Hindrances”.

    In my case, since my helper mirrors the intended use – as part of a platform implementation – there is no risk of such collisions occurring in the first place since I control both the class AND the helper (just as in the case of it’s original and intended use) and there are no third parties that are going to extend either the original class OR the helper with their own helpers.

  5. Correct me if I’m wrong, but this sounds like a serious need for Aspect Oriented Programming.

    Actually, without AOP, you might even get a lot of this to work in a generic way using attributes, which – as of Delphi 2010 – are also available in the native world.

    Did you try that path as well?

    –jeroen

  6. aiui the principle of AOP is good old fashioned “isolation and separation of concerns”. What I have done here is isolate my client specific property list behaviours and separated them from the general property list implementation using the mechanism of a class helper.

    That is AOP, it’s just not the sexy, exotic cross-cutting/declarative injection that people initially think of when they hear the term these days. πŸ™‚

    As for attributes, I can’t see how they would have helped here. But I should add that I find attributes particularly distasteful and their implementation in Delphi cumbersome and ugly, so I was not particularly inclined to investigate them, even if some potential use had occurred to me at the outset.

Comments are closed.