Skip to main content

C# style event handling (+delegates)

9 replies [Last post]
vikstar
Offline
Joined: 2004-04-23
Points: 0

I've been using java for over 5 years now, and have recently started learning C#. I've written a small archery scoring application for my pocketpc in .net compact framework.

While learning about and writing in C# I was introduced to its event handling and delegates. At the time I remember thinking to myself: "This could get messy, using Java interfaces for event handling is much less error prone". However, not every program written in Java is a huge enterprise monolith. I see many applications on the net in Java that are relativelly quite small (and i'm not talking about applets).

I've found that event handling in Java is quite a usefull feature. The only problem is that it takes to much developer time to write and rewrite every single multicaster that is required. That kind of code almost always acts in exactly the same way: allow add/remove of listeners, upon event send event notification to listeners.

C# style events and delegates simplify this tedious work tremendously, and although I havent touched my archery scoring program in a few months, I've recently looked back on it and had no trouble understanding the way events threaded through the program.

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
podlesh
Offline
Joined: 2004-07-26
Points: 0

I think that some helper classes would be sufficient and there is no need to extend Java language with some "function pointer" and especially not with weird type which is collection of itself.

Closures would be much better and more useful, but it's quite different thing.

hlovatt
Offline
Joined: 2003-11-18
Points: 0

See the following suggestion for Mustang:

http://forums.java.net/jive/thread.jspa?messageID=13571

Is this an alternative that people would like?

opinali
Offline
Joined: 2003-06-17
Points: 0

If you look at the draft docs for C# 2.0, it seems they discovered that delegates are not powerful enough for many tasks -- including event handling -- so C# 2.0 is getting closures to handle such tasks. It's interesting to see that the closure implementation technique they propose is basically identical to Java's inner classes; they only have a cleaner syntax, and additional source-to-bytecode compilation tricks to enable access to any local variable (which is the single limitation of inner classes, compared to closures).

denismo
Offline
Joined: 2003-06-28
Points: 0

I agree, delagates will allow developers to type less, I believe the code will look much cleaner, and it also might help save some memory when used instead of current interface-based mechanism for events subscribtion in AWT/Swing.

vikstar
Offline
Joined: 2004-04-23
Points: 0

Proof of concept. Even a few additions to the API is all that is required as opposed to a full-on language change:

[code]
/* in a Delegate.java file... */
import java.lang.reflect.*;
public class Delegate {

private Method method;
private Object owner;

private Delegate(Object owner, Method method) {
this.owner = owner;
this.method = method;
}

public static Delegate create(Object owner, String methodName)
throws NoSuchMethodException
{
return new Delegate(owner,
owner.getClass().getDeclaredMethod(methodName, EventArgs.class));
}

public void fireEvent(Object sender, EventArgs args) {
try {
method.invoke(owner, sender, args);
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {}
}

}
[/code]
[code]
/* in an EventHandler.java file... */
import java.util.*;
public class EventHandler {

private List delegates;

public EventHandler() {
delegates = new ArrayList();
}

public void addDelegate(Delegate d) {
delegates.add(d);
}

public void removeDelegate(Delegate d) {
delegates.remove(d);
}

public void fireEvent(Object sender, EventArgs args) {
for (Delegate d: delegates) {
d.fireEvent(sender, args);
}
}

}
[/code]
[code]
/* in an EventArgs.java file... */
public abstract class EventArgs {
}
[/code]

Then you could write something like this:
[code]
public class LightBulb {
public EventHandler switchEventHandler;
private switchedOn = false;
public void toggleSwitch() {
switchedOn = !switchedOn;
switchEventHandler.fireEvent(this, new SwitchEventArgs(switchedOn);
}

public static class SwitchEventArgs extends EventArgs {
public boolean switchedOn;
public SwitchEventArgs(boolean switchedOn) {
this.switchedOn = switchedOn;
}
}
}
[/code]
[code]
LightBulb bulb = new LightBulb();
/* "someMethod" must have signature: someMethod(Object, EventArgs); */
bulb.switchEventHandler.add(new Delegate(myObject, "someMethod");
bulb.toggleSwitch();
[/code]

Ok, the previous code might not compile, it exposes fields and the SwitchEventArgs isn't entirely necessary, but it is only ment as a proof of concept. You could event get rid of the Delegate exposure and simply convert the addDelegate and removeDelegate methods to have signature xxxxDelegate(Object owner, String methodName) and create their own delegate objects for storage in the list.

With proper delegates you could check at compile time for correct method signature supplied to the Delegate create method, or simply use some sort of annotation to ensure correct signature.

Message was edited by: vikstar

patrikbeno
Offline
Joined: 2004-10-11
Points: 0

Sounds good.

But you are not able to refactor such code. Hardcoded method names should be avoided unless there is no other choice.

Maybe we need type-safe way to obtain Method instances (and all other reflection parts as well)...

denisw
Offline
Joined: 2005-01-03
Points: 0

I think delegates should be implemented like this class:
package java.lang;
import java.lang.reflect.*;

public abstract class Delegate {
private Object target;
private Method method;

public Delegate(Object target, String methodName, Class... parameterTypes) throws NoSuchMethodException {
this.target = target;
this.method = target.class.getMethod(methodName, parameterTypes);

// i don't know if this works...
if (this.getParameterTypes() != method.getParamterTypes() || this.getReturnType() != method.getReturnType()) {
throw new DelegateException();
}
}

public abstract Class[] getParameterTypes();

public abstract Class getReturnType();

public Object call(Object... args) throws [SomeException] {
method.invoke(target, args);
}
}

This is the best way without adding features to the language. But this would be the better way:

public delegate void Foo(String bar);

bjb
Offline
Joined: 2003-06-12
Points: 0

This is some 1.4 introduced concept (thanks to class Proxy) that try to prevent the creations of tons of
http://java.sun.com/j2se/1.5.0/docs/api/java/beans/EventHandler.html

For the other part you are talking about, there should be a quite generic "EventContainer" class that should handle the a default implementation of the event container.

About the multicaster, such a class exist, but it is quite limited to the AWTEvent right now ...
http://java.sun.com/j2se/1.5.0/docs/api/java/awt/AWTEventMulticaster.html

Maybe mustang should bring something more generic.

By the way, what about having some king of mechanism that could easilly allow you to decouple classes from javabean event model and allow this thing to be decoupled with some JMS implementation in the middle.

Anybody remember the Infobus ?
On the server side we have lots of frameworks to solve the application configuration issue.

But on the client side, when you want to bring a big application, everything is pretty much coupled, because of the lack of communication framework.

This leads to job that has to be done on javabeans spec ...

stalkerbrother
Offline
Joined: 2004-08-12
Points: 0

Everyone who have tried to write a lot of event handler stuff would agree with you or at some point probably get this idea themselves, so I wonder why so few has replied positively to this message.

I think an attempt should also be made to make it even better than C# (embrace and extend). Writing event handling mechanisms is a drag. A language level approach could maybe also reduce the memory footprint.