Sponsored Link •
Anders Hejlsberg: Delegates add a kind of expressiveness that you don't get with classes or interfaces, which is why I think they are important. Programming languages that have gone before us have recognized that they are important. They have many names: function pointers, member function pointers. In LISP they are closures. They are what functional programming is all about when it comes right down to it. They are tremendously useful.
Bill Venners: In what way?
Anders Hejlsberg: You can indeed do with interfaces what you do with delegates, but you are often forced to do a lot of housekeeping. Let's look at how you handle events in Java, for example, versus how you handle events in the .NET world. Because there are no delegates in Java, you end up using interfaces.
You define an interface that represents all of your events. The interface could declare one, two, three, four methods or more. Already, there's an issue. It's not particularly clear how to structure that. How many interfaces do you have for your outgoing events? Do you have one interface per event or one interface for all events? There's no clear guidance, and sometimes it falls somewhere in-between. So you fudge that one out. Now, to handle events coming out of the component, you have to implement the interface. Of course if you want to handle the same set of events from two different components, then you have to implement the interface twice, which you cannot do. In that case you need to create an adapter. This is where the housekeeping starts getting in your face.
Inner classes can help a bit with that housekeeping, but nonetheless, part of the problem with using interfaces is that the receiver of the event has to know that he is receiving the event. He has to explicitly implement the listener interface. With a delegate, by contrast, as long as the signatures are compatible, you can just slot them together. The guy handling the event doesn't care how he got called. It's just a method.
Bruce Eckel: It's sort of a weaker typing.
Anders Hejlsberg: Yeah, indeed it is.
Bruce Eckel: So it's more flexible.
Anders Hejlsberg: Yes, exactly. It's purely based on whether you have compatible signatures, i.e., parameter lists. If you do, you can wire them together. And it also conceptually completely matches the end user expectation of what happens with a call back, right? Give me some parameters and I'll write some code. Sure sounds like a method to me. Sorry, I'd like to give you a reference to that method, and that's what a delegate is.
Bruce Eckel: And yet in the end you don't lose the type checking. The type checking is happening at runtime?
Anders Hejlsberg: No, even more is happening at compile time. When you construct a delegate, you get what a C++ programmer might call a bound member function pointer. The delegate references a method of a particular object. If that method is virtual, you can actually figure out precisely which one it is going to be. So in a sense, you can resolve the virtualness at delegate construction time. The call through the delegate is literally just an indirect call instruction.
Bruce Eckel: It doesn't have the extra indirection.
Anders Hejlsberg: That's right, you can resolve the VTBL indirection once and for all when you construct the delegate, and then with every call through the delegate you're just going straight to the method. So not only can delegates be more efficient than interface dispatch, they can be more efficient than regular method dispatch.
Bruce Eckel: C# also has a multicast delegate, in which one delegate causes multiple functions to be invoked. Is that an orthogonal feature?
Anders Hejlsberg: Multicast is a completely orthogonal feature. And honestly, I am neutral on whether multicast is a great thing. I think it has its uses, but I also think we could defensively have said all delegates are single cast. Some people find multicast very important, and there are some very good uses for it, but in the vast majority of cases, delegates are just single cast. Indeed we've constructed the system such that you don't actually pay for the multicast feature unless you use it.
Bill Venners: How do delegates fit in with what you were saying before about simplicity and simplexity? Where is the simplicity and where is the simplexity?
Anders Hejlsberg: If you emulate delegates with interfaces, you end up with all this housekeeping and adapters. Indeed, look at any tool that wires together JavaBeans. They generate these adapters and say, "Don't modify this code down here. We're going to spit out these reams of funky little helper classes for you." That to me is simplexity. The system is not truly simple. The system is actually quite complex, but if you squint it appears to be simple.