Monday, May 08, 2006

Class Helpers - good or bad ?

Moved here

9 Comments:

Anonymous 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.

10:11 pm  
Anonymous Anonymous said...

Brilliant article

10:59 pm  
Anonymous 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...

5:29 pm  
Blogger 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!

7:14 am  
Blogger 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.

9:21 am  
Blogger TOndrej said...

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

11:23 am  
Anonymous 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 helper_for_x, since this is the only way to avoid to scan _all_ units in the entire project for helpers to compile a unit.

9:57 am  
Anonymous Jolyon Smith said...

An old post that needs a sensible comment.

Class Helpers are to be considered "bad" when used in an application because they were never designed for general purpose use, and exist solely to workaround a design problem in the VCL that ONLY existed for the language (or more accurately, the VCL) implementors, not those who implement USING the VCL.

The biggest problem with class helpers, from the p.o.v of using them in your own applications, is the fact that only ONE class helper for a given class may be in scope at any time.

That is, if you have two helpers in scope, only ONE will be recognised by the compiler. You won't get any warnings or even hints about any other helpers that may be hidden.

So you can happily code away with your lovingly crafted helper, then you start using some other unit that contains someone else's helper for the same class and suddenly your helper is no longer "visible".

Of course, since helpers are used - as designed - within the VCL, adding helper classes for VCL classes is most likely to experience this problem.


You may be able to fudge your way out of it by fiddling with the order of your units in the uses list. Or perhaps moving the "help point" of one or other helper up or down the ancestry of the helped class (assuming and hoping that that does not in turn create a conflict with some OTHER helper out there).

If you can't then you are stuck, because you can't even use qualification to forcibly reference the "hidden" helper.

TMyHelper(obj).MyMethod;

Won't compile if TMyHelper is "hidden" by some other helper for the class of obj. In fact, it doesn't work period, because TMyHelper does not exist as a type, so you can't even use this style to aid clarity with bona-fide helpers at all.


There is of course an alternative, which is not only immune from all these problems, but is also actually more flexible/powerful and works even in older versions of Delphi.

That is, to use explicit helper-style sub-classes, the old fashioned way, where you adhere to the rules for helpers (only accessing public methods, not adding instance data etc etc) but use explicit hard-casting to "add" your methods to an instance.

TMyHelper = class(TForm)
procedure MyMethod;
end;


TMyHelper(form).MyMethod;

This is "better" because:

a) it IS explicit. No magic. No wondering where these undocumented methods came from (for the uninitiated, unaware of the existence of your "helper" class is some obscure unit somewhere)

b) it is unbreakable. As long as you stick to the safety rules for implementing the helper itself, nobody else's helper can "hide" yours or interfere with how it works.

c) it is more powerful and more flexible - the "helper" subclass is able to access protected AND public members.


One arguable downside is the need to explicitly cast in order to invoke your helpers functionality.

But that could equally be argued to be a further ADVANTAGE, since it makes it clear that an instance is being treated as something that it strictly isn't.

True, it may involve a little more typing than using a bona-fide helper.

So which you prefer will come down to whether you place more value on saving a few milliseconds of typing time vs potentially hours or even days of refactoring if (more likely "when") you get a "collision" among your helpers.

11:13 pm  
Anonymous Anonymous said...

@Jolyon Smith: Nice comment!

I think it would be worth addressing Jolyon's points in the article so they don't get lost in the comments.

1:41 am  

Post a Comment

Links to this post:

Create a Link

<< Home