Anonymous Methods – When Should They Be Used?

Anonymous methods are generating a lot of buzz in the Delphi community right now, being one of the bigger changes heading our way in the forthcoming Tiburon (Delphi 2009), along with Unicode and Generics.

Unlike Unicode and Generics however, the usefulness of anonymous methods is not nearly as clear.

On Joel On Software

Joel On Software has been invoked as an authority.  Unfortunately, as Joel himself has previously admitted, he does not actually use Delphi, and a great deal of the usefulness he sees in anonymous methods seems to stem from this fact, in that what he describes as the principal benefits of anonymous methods has always been achievable in Delphi.

To paraphrase his material on this point:

    procedure Cook(const aIngredient1, aIngredient2: String;
                   const aCookingMethod: TCookingMethod);
    begin
      Alert('get the ' + aIngredient);
      aCookingMethod(aIngredient1);
      aCookingMethod(aIngredient2);
    end;

Cook( 'lobster', 'water',   PutInPot );
Cook( 'chicken', 'coconut', BoomBoom );

Joel asks: Can your language do this?

If the language is Delphi, yes.  We don’t need anonymous methods for this.

But that is not the only use for anonymous methods espoused by Joel.  He goes on to talk briefly about threading, before seeming to me to go off at something of a tangent to talk about MapReduce, where the applicability of anonymous methods is a little hard to fathom (in the context of languages that “can do this”) and I’m certain that the actual Google MapReduce implementation is a great deal more complex than Joel’s summary, but I’m not so sure that anonymous methods were critical to it’s success, rather than just happening to be a part of it.

One wonders if they would have featured at all if Google had used Delphi.  :)

Anonymous Methods and Threading

In a different blog, Lars Fosdal also mentions threading.

Coming at the subject with the Delphi perspective that Joel does not have, Lars aligns the benefits of anonymous methods against the failings of TThread.  Not unreasonable, given that TThread is the “out of the box” approach to threading in Delphi and it undeniably has a number of shortcomings.  But TThread is not the only game in town for Delphi developers.  I myself have needed a more lightweight approach to threading in the past.  So I made one.  I called it TMotile (a work by Peter F Hamilton brought the term motile to my attention, and the fit was obvious in my mind).

My TMotile class can be used in two ways.  First to execute some procedure in a fire-and-forget background thread:

    procedure SomeProcedure;
    begin
      // ...
    end;

TMotile.Execute( SomeProcedure );

Or secondly in a way perhaps more familiar to those already used to TThread:

    TMyMotile = class( TMotile )
    protected
      procedure Execute; override;
    end;

    procedure TMyMotile.Execute;
    begin
      // ...
    end;

TMyMotile.Create;

With anonymous methods that fire-and-forget usage could be made simpler:

TMotile.Execute( procedure
                 begin
                   // ...
                 end; );

Of course, that “simpler” observation is, I think, debatable.  If it is “simpler” at all, then actually it isn’t by very much, and arguably it introduces an unacceptable level of noise into the code.  This doesn’t appear to be the case when viewed in isolation, but in the context of a longer sequence of code where only one statement is invoked to create a thread to handle background execution of some other code, seeing the body of that background code is “noise”.

There is an even greater advantage when the body of the anonymous procedure captures state from the context in which it is created.  In those situations then this usage simply cannot work without anonymous methods, requiring a subclass of TMotile (or TThread) in order to explicitly capture that state from the context and make it available to the threaded procedure:

    TMyMotile = class(TMotile)
    private
      fContextVar: ...;
    protected
      procedure Execute;
    public
      property ContextVar: .. write fContextVar;
    end;

    procedure TMyMotile.Execute;
    begin
      ..  fContextVar  ..;
    end;

mm := TMyMotile.Create;
mm.ContextVar1 := SomeContextValue;
mm.Execute;

Which can be replaced with:

mm := TMotile.Execute( procedure;
                       begin
                         .. SomeContextValue ..;
                       end; );

Which is undeniably neat. Both in the sense that is it clever and a great deal more concise.  But I am still not convinced that this convenience is worth getting all that excited about – It has not enabled anything that was previously impossible, nor even especially difficult either to implement or to understand, and that noise is still there.

Indeed, anonymous methods do not even eradicate the infrastructure that is required to support it, they just hide it.

If it’s hidden, I can’t fix it or improve it or adapt it to better suit a specific use.  If it’s hidden I may never the less need to take it into account to understand what unfamiliar code does and how – hiding it just makes it that much harder to identify and requires me to bring that knowledge of the hidden details with me.

For one thing of course, if this threaded code should later evolve and require some mechanism to pass information back to the context that originated it – or some other context – having that threaded code represented by an identified and referencable object provides exactly the mechanism we need.  Without any such visible device, yet more wizardry is needed to provide that mechanism without resorting to simply exposing and extending the pretty basic infrastructure.

With Great Anonymity Comes Great Responsibility

Having anonymous methods in the language does not compel us to use them, and unlike Generics or even Unicode to an extent, using them in your code will not compel others to use them either, if they do not wish to.  So what’s the harm?

Well, of course, the same could be said of with – and indeed, the similarity is quite striking.  Both provide a means of hiding an implementation detail and avoiding the onerous task of encumbering that detail with an identity.  with is, somewhat famously, regarded with disdain for the way that this hiding of details introduces problems.  Not least when debugging (and the prospect of debugging anonymous methods is similarly intriguing, to say the least).

So if we all only use anonymous methods responsibly, we’ll be fine.

Which call to mind Eddie Izzard’s response to the NRA’s assertion that “Guns don’t kill people, people kill people” …..

…and monkeys do too (if they have a gun)

Speaking of Eddie Izzard, if you haven’t heard his Death Star Canteen sketch, then allow YouTube to introduce you to in glorious LegoVision.

Any excuse.  :)

Other Parallels

No not a further examination of threading, but the use of one thing to draw a parallel, or a comparison, with something else.  In this case, let us imagine we are putting together a web site, and on some of our pages we have some content that isn’t directly relevant to the page it is on.  Content that certainly doesn’t have to be read at the time, but which perhaps isn’t likely ever to be read alone.  It’s not going to appear in our site navigation or even the table of contents necessarily.

It’s content, but it doesn’t have an absolute identity outside of some other context in which it is referenced.  On the printed page, it would be a footnote or an entry in the bibliography.

These things to a written language are, essentially, what anonymous methods are to our code.

So why do we have footnotes?  Why do we use links in web pages, instead of just quoting, verbatim and inline, the content we would like the reader to perhaps come back to later, and just require them to skip over it in the meantime.

The question is of course rhetorical.

This is essentially what anonymous methods will bring to your source code.

I may never write code this way myself, but I am not looking forward to the first time I have to read someone else’s code written that way.

So, When Should They Be Used?

The title of this post posed a question, and it’s only fair that I answer it.

As things stand, I would have to say that anonymous methods should be used only when you absolutely have to, and so far I have not yet seen an example where anonymous methods are the only way to achieve anything.

I may yet change my mind, and more examples have been promised by CodeGear.  But CodeGear didn’t invent these things, and they aren’t new, as plenty of people point out – compelling and obvious examples should already be readily available, albeit not in Delphi.

Where are they?

Tags: , , , , ,

8 comments

  1. CR’s avatar

    Good post. At the current time, the only thing that seems a clear benefit with anonymous methods being brought in (and even then only a minor one) is the side effect of a new procedure type agonistic between global routines and methods. That said, I look forward to seeing answers to your closing question putting me right though!

    PS – you should get your blog aggregated by the Delphi Feeds site to allow more people to realise it exists.

  2. hello’s avatar

    In Ruby, blocks are closures, i.e. what is called anonymous methods in Delphi. It can be used in iterator methods which yield values from the block.

  3. Jolyon Smith’s avatar

    Thanks for the comments CR.

    I hope to get onto DelphiFeeds at some point, but usually a blog has to have been running for a while (3-6 months) to qualify. I may approach them in a few weeks though to see if my content up to that point is considered good enough to warrant an exemption.

    In the meantime, tell your friends.

    :)

  4. Jolyon Smith’s avatar

    Hello “hello”.. thanks for the comment.

    I am supposing that you are offering Ruby as an example where anonymous methods already exist and provide the “real” examples I asked for.

    A fair point in it’s way, but if was writing the sort of code that Ruby is useful for, or if Ruby was well suited to the sorts of application I do write, I would already be using Ruby.

    So I guess what I am really asking for is “examples that I can see apply to the way I use Delphi and the sort of code I work with”.

  5. Lars Fosdal’s avatar

    Good article. As you know, I see the anon.methods in a slightly different light. The anonymity is only apparent from the framework side, ie the plumbing that you pass your code into, while in your code – it is at the center of attention. It is defined and passed to the framework at the location where it is being used.

    You ask why we use links in web pages, instead of quoting? When we describe code – we actually do quote for clarity. Without anon.methods, we are forced to “link” to our code (ie refer to some other function), instead of “quoting” what we want to do at the place we want to do it.

    P.S. Your name is well known in delphi.non-tech, and I am sure that Dennis Gurock would not have any issues with adding you to the Delphifeeds list. It never hurts to ask :)

  6. Jolyon Smith’s avatar

    Thanks Lars. I see what you mean about the anonymity being apparent (or not, if you see what I mean :) ) on the framework side, but to that extent anonymous methods are no more anonymous than the current ability to pass a method reference.

    Surely the anonymous method name stems from the fact that the method reference being passed by reference will no longer need to have an identity, i.e. the anonymity apparent (again, or not) from the consumer side of the framework?

    Re your PS – I have no doubt that my name isn’t well known in non-tech, although I’m not so sure whether that would count in my favour or against me! ;)

    This blog is, in part at least, an attempt to rehabilitate myself in the community.

    :)

  7. Maël Hörz’s avatar

    Well written! I mostly had the same thoughts when reading the “Joel on Software” post.

    So far the only use I can see for anonymous methods is when they are really succinct. For example a sort function that requires a comparison method as argument.

  8. Caleb’s avatar

    (disclaimer: I have a fair bit of experience in both Delphi and Python)

    You mostly get the idea, and I like the demonstration comparing storing state in a class vs. in a closure (“anonymous method” is such a dumb name – I wonder whether this was introduced because it got too difficult to distinguish between .NET 1, .NET 2 and .NET 3 versions of delegates?), and that is a very good way to understand the mechanism, i.e. an alternative method of binding state and action. However, some points:

    1. It will be easier, in general, to manage concurrency with closures, than for storing state via class fields, because the “external references” will have been “captured” by the closure, i.e. they can’t change inside the closure. This is not a Delphi-specific thing, and I don’t know if there are plans to put such guarantees or checks in the compiler, or anything like that, but this is how functional programming languages approach concurrency – closures with no side effects. Within methods (object methods), side effects from inside the method scope are not only easy, but even normal (this is the OOP paradigm). You’re very close to seeing the benefit of closures for concurrency with your

    mm := TMotile.Execute( procedure; begin end; );

    example; now just try to see that the closure you just defined can be *intrinsically* thread-safe, because all the state it needs has been bound and made available at the perfect place :) . (I don’t know how side-effects are managed in Tiburon, just giving a brief description of the closure-concurrency relationship as it might apply to Delphi)

    2. In addition to concurrency, closures are very often used for event programming. For instance, a commonly used example is when, say, you want to remember something during a mouse-down, and recall it during mouse-up (e.g. drag-n-drop). With classes, you would store the data in a field and recall it later, whereas with closures, you write the mouse-up event handler inside the mouse-down event (capture context-specific state too), and assign the method pointer to the mouse-up event slot. Again, two different approaches. Technical merits of each aside, it is informative to think about different ways of doing things. My personal opinion is that this is a far more intuitive and logical means of writing connected events than storing temporary data inside an object instance, but ymmv.

    3. I disagree that with closures, anything has been “hidden”, or maybe I fail to understand what you mean (the method name?). I also disagree that closures are “simpler” in some sense. They are simply another method of binding state and action, that’s all.

    4. The “with” strawman is not convincing. The problem with “with” is the possibility (indeed, likelihood, in large projects!) of namespace collisions, not the fact that information is hidden, per se. There is no similarity with closures. Again, the fact that the closures do not have names, or that they are called “anonymous methods” in *this* implementation has nothing to do with the functionality -> which is the binding of state and function. “Anonymous methods” is a really dumb name. Almost as dumb as “Lambda expressions”, but at least there is a hint there that something else is going.

    5. I disagree that closures should only be used when one *has* to. I would rather promote that closures should be assignable (and used) throughout the Delphi event subsystem. As far as I know, according to Andreano Lanusse and Barry Kelly, this is not (yet) possible. Using closures as events would clean up many class declarations of fields that are simply there to propagate state from one event handler to another.

    6. You neglected to mention that Delphi already has a type of “closure”—not the function pointers of your “Cook” example above, but rather nested functions and procedures. However, they are dangerous because they do not *bind* the enclosing scope, i.e. A nested function that refers to local variables in the parent function will continue to use the newly updated values of those local variables throughout the execution path of the parent function. This would be where angels fear to tread.

    7. Everyone knows generics and closures are coming to Delphi Win32 because they are required in Delphi.NET which is required to support C#/.NET dynamic features. This is obvious, and a given. That said, some of those features, like closures, might prove worthwhile in spite of their origins. I am less enthusiastic about generics, which, imho is just a typing-saver and is likely to make debugging more difficult. Closures will also make debugging more difficult (where do you set the breakpoint???) but the advantages are a little clearer. At least for me.

    On the whole, a good post, and clearly written. I note that you have not outright said “anonymous methods are bad!”, but have rather chosen to require evidence, and this is a good thing.

    (I’m probably not going to swing by here and read replies to this comment, unless I get a DelphiFeeds update…)

    Cheers
    Caleb

Comments are now closed.