Sending events using closures Can someone please explain type inference to me?
Sep 24

In almost every discussion about the new closures proposal, I see a lot of people comparing closures to delegates, and/or complaining that just because C#/.NET has it, Java doesn’t have to follow. On the latter I will not remark; but regarding a comparison, let’s make a fair comparison between the two (considering, of course, that C#’s delegates feature is already on the market for a couple of years now, and Java’s closures are just a proposal at the moment).

Let’s start with the easy parts:

What’s similar between the language features

  • Pointers to functions. It’s clear that both denote a “pointer to a function”, whether it’s an ad-hoc function (anonymous delegate as of C# 2.0 and closure literal in Java), or an encapsulation for delayed invocation of a class method (even though I couldn’t figure out from the proposal how this is done using closures).
  • Anonymous methods. As said before, both have the ability to create anonymous methods. The syntax in both is almost the same, as well, except that in C# you can omit the parameters’ declarations if none of them are used.
  • Covariance support. Both languages support covariancethis means that a closure of type { int => String } can be assigned to function-type { int => Object }.
  • Contravariance support. Almost the same as the previous one, contravariance means that a closure of type { Object, EventArgs => void } could be assigned to function-type { Object, MouseEventArgs => void }. This is helpful, for example, when one method is to deal with all types of events (in the terms of the example given), without need to know what kind of event it was.

Now for the fun part:

Stuff the Java proposal shines on

  • Distinct and global definition of function-types. A definition of a function-type is global to compiled Java applications, meaning that a function-type { int => int } will always be compiled to the same interface, and will used the same everywhere. These function types are defined “ad-hoc”, meaning that there is no need to define them separately. This is contrary to C#, where delegates need to be defined in a separate scope than a method’s definition. This, and the fact that delegates cannot be defined inside interfaces, causes the side-effect of having to define delegates in a global scope if they are needed in an interface and are not defined elsewhere. It is worth to note that with the upcoming release of Lambdas in C# 3.0, pre-defined delegates called Func were added to make most of the definitions easier.
  • Conversion between interfaces and closures. The proposal allows to convert between an interface having a single method and a closure, preventing the need to create the obvious boiler plate code for manual conversion (i.e. { => void myRunnable.run() }). This also (and primarily, I suppose) allows old APIs to be upgraded to use closures without breaking existing code.
  • Control invocation. This allows closures to be used as blocks for a pseudo-control-statement, such as a with method (to emulate C#’s using), or a doLater statement that could emulate JavaFX’s doLater keyword. This might look like:
    
    doLater() {
      // some code
    }
    

    Where the code inside is inferred to be a closure of a certain type, defined in the doLater method.

Now for some of the features in C#/.NET that I might miss

  • Events as a language-feature. This is important, as closures will be (or at least should be) used for events as well, instead of anonymous class implementations of listeners. In C#, events are a language-feature, meaning an event can be defined in a class or interface, delegates could be added to it, and when the event is called (by invocation similar to invoking a delegate), all chained delegates are called. This makes events a lot easier to implement, and prevents a lot of boiler-plate code. I had my own idea on events through closures, but it’s not completely thought through, and obviously not in the closures proposal.
  • Assigning class methods to a suitable delegate. This is just plainly missing from the closures proposal. This means that I can assign any method from a class to a suitable closure, such as { => long } hasher = anInstance.hashCode.method. This is especially useful when a certain concrete method of a class is the wanted target for an event being fired.

Miscellaneous

  • Invocation. Invocation of delegates is done just like calling a method, i.e. myDelegate(x, y), where in the closures proposal it’s invoking a method in the closure object - myClosure.invoke(x, y).
  • Template delegates. It is possible to define a template delegate, i.e. delegate MyDelegate<T>(T t). In closures it’s not needed as there are no “named closures”, and covariance and contravariance will take care of the rest.

I’m sure there are more differences, but these are the ones that come to mind at the moment. I’d appreciate anyone’s thoughts on the matter, as well!

Share/Save/Bookmark

3 Responses to “I say, delegates shmelegates: Delegates vs. Closures”

  1. Alex Miller - Java 7 Roundup (Sept 24th) Says:

    [...] Chaotic Java has been on a tear the last few days with several interesting Java language posts. First up, he blogged about a couple proposals to indicate whether nulls are accepted, and then took on sending events using closures, and C# delegates vs Java closures. All good and interesting stuff worthy of your attention. [...]

  2. Cyrus Najmabadi Says:

    ChaoticJava, i’m confused about one of your subpoints of ‘Stuff the Java proposal shines on’, specifically : ‘Conversion between interfaces and closures’

    Let’s consider a real example:

    void Foo(Func f)

    IComparable c = …;

    In C#, to call Foo all you need to do is:

    Foo(c.CompareTo);

    I’m not seeing how Java ‘Shines’ here. Could you clarify this point?

  3. Avah Says:

    Cyrus: That point means that not only can I pass “c.CompareTo”. It means that if IComparable contains only one method, I can just pass “c”.

    That is great for a lot of backward compatability issues, where closures can be placed instead of those one-method calls. This allows Java as a framework to have closures in the oldest of the APIs, instead of developing a whole new set of parallel APIs (i.e. System.Collections.Generics vs. System.Collections).

Leave a Reply

Chaotic Java is Digg proof thanks to caching by WP Super Cache!