Mar 06

In his post, Amr from EJUGS points out that he tries to implement the powerful delegates of C# in Java, in his words. Even though I am a C# developer as well, and see the power they serve, I don’t agree with some of his claims.

First, both papers are still relevant even though old. I agree with both almost completely. The thing is, Microsoft doesn’t address the fact that delegates take a lot of the object-oriented out of the language. Sun, on the other hand, aren’t pure either.

In C#, when you write the keyword “delegate”, a class is created to wrap any arbitary number of methods with the same signature. The compiler is the one making sure the signature is the same, as this wrapper class only receives an object (to invoke on) and a method identifier (to invoke). Then, when the delegate is invoked, it actually uses reflective methods to invoke the method(s). No wonder Amr claims that [most] implementations uses reflection to invoke the method.

Is that considered powerful? Java on the hand, since it uses classes implementing a single interface, is using direct invocation, and doesn’t use reflection (which known to be extremely slow) in any part of it. Since annonymous classes can be used, the amount of written code isn’t that bigger: Even by Microsoft’s blown measurements, it was increased by less than 10%, which is in most likelihood the new ActionListener() { lines.

In Amr’s implementation of the Delegate class, he hard-wired the method Job to be with the signature of Job(Stirng). That means a new Delegate class implemented, with all his code, for every signature. That said, he claims to have a better version that doesn’t. If he does, I wish to see how it’s implemented – Out of my own curiousity, and to see that it doesn’t prevent type-safety, as I suspect it does.

I don’t mean to bash out at Amr’s work. It’s good that people try to innovatively add abilities to the Java language. However, what makes delegates work in C# is not the language but rather the dotNet compilers. Without creating a good pre-compiler for Java, delegates would not be introduced in the same “powerful way”.

If you ask me, I don’t think they should be in Java. There’s a reason why they stayed out, even though as the papers show Sun and Microsoft had the fight about it way back in 1998. The reason is object-oriented design, and the “magic factory”. In any case, Java events are implemented using the observer-observable design pattern. I think what we should do is focus on easier implementations of this design pattern. I know I’m not very objective, but the ListenersCollection class is a good example.

This is the second time I say something in response to EJUGS… I hope they don’t hate me over there by now..

Related Posts with Thumbnails
Share

7 Responses to “Delegates in Java – Why not?”

  1. Jesse Wilson Says:

    There is no technical reason why delegates must be implemented using reflection. Reflective delegates are slower but don’t require custom .class files for each delegate.

    Regardless of how they’re implemented, I think delegates can be very useful. Throughout a project I’m working on, we do a lot of binding using reflection and JavaBeans. Here’s some code using the JGoodies binding layer:
    Customer customer = new Customer();
    BeanAdapter customerBeanAdapter = new BeanAdapter(myCustomer, true);
    JTextField customerName = new JTextField();
    Bindings.bind(customerName, customerBeanAdapter.getValueModel(“name”)); // uses Customer.getName()
    JTextField customerAddress = new JTextField();
    Bindings.bind(customerAddress, customerBeanAdapter.getValueModel(“address”)); // uses Customer.getAddress()

    This code works great. But if I rename the ‘address’ property on my Customer class, the compiler doesn’t remind me to fix everything that’s accessing that property reflectively. If we had language support for delegates, we could make our tools more powerful by giving them more information.

  2. Avah Says:

    Delegates aren’t the answer for everything. In your example, they wouldn’t work as the “bind” method should get a proper method signature. “name” and “address” might both be strings, but a different bind might require binding to the “age” property.

    On the issue of delegates not having to be called reflectively, not making them reflective would be such a hassle to the compiler and might reduce some of their properties in their current dotNet implementation (such as them being able to call a private method if passed out as a delegate).. They’re implemented using reflection in dotNet and it seems like it’s going to stay that way.

  3. Paul Murray Says:

    I thought this was about something else.

    I deeply wish that java had a language feature like this:

    interface Bar {
    int bar1(); int bar2();
    }

    class Foo implements Bar {
    Bar myDelegate implements Bar;
    }

    The “implements …” after the variable initialisation or a method throws clause means that calls to methods on Bar will autimatically be delegated. This is a compiler feature: the compiler generates the following:

    class Foo implements Bar {
    Bar myDelegate;
    public int bar1() { myDelegate.bar1(); }
    public int bar2() { myDelegate.bar2(); }
    }

    And I’d like it to be available on methods, too:

    class Baz implements Bar {
    Bar a, b;
    Bar getDelegate() implements Bar {
    if(moonphase=full) return a; else return b;
    }
    }

    which would cause the methods
    public int bar1() {getDelegate().bar1();}
    public int bar2() {getDelegate().bar2();}

    to be generated.

    The motivation for this is that writing classes that delegate most of their functionality somewhere else is a pain in the proverbial.

  4. Avah Says:

    I can understand the motivation for this. Interesting concept!

    For a long time I figured such things as automatic delegation are needed, especially since delegating tasks to helper classes is the most reasonable way to avoid unneccessary class inheritence.

    I also thought about easier handling of chained exceptions. On some cases, you’d want to handle an exception only if its Inner exception is a certain type of exception. This is true especially in API frameworks which usually provide some parent-level exception such as MyAPIException and wrap all I/O, parsing, reflection and anything else as an inner exception of the MyAPIException.

    So instead of:

    try {
    // do my stuff
    } catch (MyAPIException e) {
    Exception inner = e.getCause();

    if (inner instanceof IOException) {
    // handle
    } else if (inner instanceof OtherException) {
    // handle
    }
    }

    This can be easily replaced with:

    try {
    // do my stuff
    } catch (MyAPIException : IOException e) {
    // handle internal IOException
    } catch (MyAPIException : OtherException e) {
    // handle internal OtherException
    }

    Also, the wrapping could be made easier, so that instead of writing a try/catch for the entire exception-wrapped code, it would be wrapped automatically. Instead of:

    try {
    // read from file

    // cause some exception
    } catch (FileNotFoundException e) {
    // really handle this one
    } catch (OtherException e) {
    throw new MyAPIException(e);
    } catch (IOException e) {
    throw new MyAPIException(e);
    }
    We could write:

    try {
    // read something

    // cause some exception
    } catch (FileNotFoundException e) {
    // really handle this one
    } throw MyAPIException for { IOException, OtherException }

    What do you think?

  5. Avah Says:

    I wanted to write a correction – dotNet doesn’t use reflection in order to invoke typed delegates. It seems it holds a direct function pointer and uses that, instead, making things much faster.

    However, all my other points (Regarding weak references, for example) and a new point which I’ll make now, still seems valid.

    The new point is this: The use of delegates for events is an instantiation mess in some cases. If there is a set of events an API user would like to listen to (for example, mouse events which are usually the Up, Down, Move, Click events), using interfaces he will only need to instantiate one instance, and using delegates it would be four (one for each delegate instance).

  6. Justin Grant Says:

    I have a C# background but am in the middle of learning Java, so the discussion above was very useful for me to understand the equivalent to delegates in Java. Thanks for the pointer to anonymous classes, which apparently allow similar kinds of operations in Java. Thanks!

    I’ve got a question for you guys about syntax. In C# you can easily pass parameters to a delegate, can return a typed value from a delegate, and (after C# 2.0) can easily define a delegate implementation using inline code inside another method, and that inline code can access local variables from the containing method. Can Java do something similar?

    For example, to create a filtered copy of a List collection you use the List.FindAll(Predicate) method. Predicate is a delegate type which accepts a single argument of type T and returns a boolean. The FindAll() method calls the delegate for each element and returns a filtered collection containing only the elements for which the Predicate delegate returned true.

    Here’s sample code which creates a filtered copy of a collection where only elements divisible by a particular number are included. I showed syntax for C# 2.0 (using anonymous methods) and C# 3.0 (using Lambda expression syntax).

    int divisor = 3;
    List nums = new List { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    List CSharpV2 = nums.FindAll(delegate(int n) { return n % divisor == 0; });
    List CSharpV3 = nums.FindAll(n => (n % divisor == 0));

    Can something similar be done in Java? By “something similar” I mean “syntax for easily passing inline code to another method, where the inline code defines a method which: takes 0+ parameters; can optionally return a strongly-typed value; and can access local variables from the containing method”.

    I suspect the answer is “yes using anonymous classes inherited from another class, but the syntax is more verbose than C#” but am not sure about the details and caveats.

  7. Aviad Says:

    @Justin: You already gave yourself a good answer; today, you’d have to use annonymous classes and in fact the example you gave exists – just look at the Comparator interface and implementations of the SortedSet interface (such as the TreeSet).

    The plans for Java 7 include “closures“, which are more like the C# 3.0′s Lambdas than delegates, but just like the lambdas can replace annonymous classes when callback logic is required.

    Hope this helps!