6

When is it useful to have multicast delegates over singlecast delegates?

I use delegates a lot, mainly coupled with C# lambdas, but I've never felt the urge to use the multicast aspect of C# delegates, ie I've never wanted to combine multiple delegates together in a single delegate. I'm therefore very curious in what sort of situation multicast delegates are useful - I can only think of examples in which you can easily implement the functionality some other way, by, say, chaining the delegates or putting them in a list.

In particular, Eric Lippert's answer here gives the impression even the C# team sometimes forgets about the multicastiness of delegates.

Community
  • 1
  • 1
Alex ten Brink
  • 879
  • 2
  • 8
  • 18
  • 4
    I long for a day when I can forget about the multicastiness of delegates. – Eric Lippert Jun 09 '11 at 19:57
  • Well, that piques my interest - any particular reason why? Multicasty delegates are at least as hard to implement as singlecasty delegates, but is it really very bad, or is the issue with variance a bad memory? – Alex ten Brink Jun 09 '11 at 20:27
  • 5
    @Alex: Multicast delegates are in my opinion simply unnecessary in a world with collection types. There is no justification in my mind that the "sum" of two delegates is a third delegate that invokes the first two. I would prefer to explicitly implement events as some sort of collection of delegates. The "multicast delegate" concept is an unnecessary increase in the "concept count" of .NET; we can get by just fine without it, and it simplifies life considerably if you do so. But of course we are stuck with them now, and have to live with their oddities. – Eric Lippert Jun 09 '11 at 20:46
  • 1
    Then again, MulticastDelegate stores the delegate targets in a list :) – Hans Passant Jun 10 '11 at 06:04
  • @Eric, surely there is utility in the act of initiating the execution of single/multiple delegates via the same 'interface' for want of a better word. Or would you (in the hypothetical alternative) keep the sugar? Using externalised colelctions would have the benefiit of allowing you to change the multicast behaviour (on exceptions/ordering/on edits) but you'd still want something that did 'the right normal thing' by default. I hate that java forces you to implement multicasting everytime (with the usual semi random scattering of bugs in the subtle edge cases) – ShuggyCoUk Jun 10 '11 at 11:50
  • @ShuggyCoUk: Sure, there is utility; otherwise the feature would not have been implemented in the first place. But the feature is basically to special-case delegates in a strange way. There is also benefit to, say, lifting integers to sequences. We could say that the sum of two integers is a sequence containing those two integers, and the sum of an integer and a sequence is a third sequence, and so on, and have a lovely syntax for sequences of integers, but we don't do that for any type other than delegates. – Eric Lippert Jun 10 '11 at 14:22
  • @Eric, @Shuggy - I find the existence of multicast delegates which are not void-returning particularly strange. When calling such a delegate, is there a reasonable semantics regarding which result should be returned? – kvb Jun 10 '11 at 15:16
  • @kvb I like the idea of the semantics of that being pushed into the 'composting' type. However I would still want the immutable semantics of the current implementation, as well as there being a root type/interface to both the single delegate and the composite delegate container such that the foo() sugar for foo.Invoke() was retained. I'm not sure how easy that would be given generics without compile time generation of the container types (or variadic generic type support). – ShuggyCoUk Jun 10 '11 at 15:47
  • The alternate is to compose them via closures, which seems somewhat ugly but then I can't see how you can cleanly remove callees from the chain. – ShuggyCoUk Jun 10 '11 at 15:47
  • @Eric Am I incorrect in thinking that there is more to Multicast delegates than just sugar, or do you think being able to treat the use of a composite as equivalent in all respects to a singular form from the point of view of consuming code is not worth the required internal gymnastics? I recall either in 1.0 or 1.1 the invocation of a multicast chain of length n was O(n^2) due to repeated traversal – ShuggyCoUk Jun 10 '11 at 15:50
  • @kvb _"which result should be returned?"_ See the comments to the answer by Marc Gravell. – Jeppe Stig Nielsen Nov 12 '12 at 12:20
  • @JeppeStigNielsen - That says which value _is_ returned, but doesn't address the philosophical issue of whether it ever makes sense to call a multicast delegate with a non-void return type, given that all but one of the results will necessarily be discarded. – kvb Nov 12 '12 at 15:28
  • @kvb I agree! If they were to create a new type system where they distinguished between "unicast" and multicast delegates, then they ought to consider allowing only `void`-returning multicast delegates. However, they ended up having all delegates in .NET being multicast. The order of execution of the items in the invocation list might be significant for many other reasons (than return value), though. – Jeppe Stig Nielsen Nov 12 '12 at 16:27

2 Answers2

8

Anything acting as an event is the classic answer here - then the caller doesn't need to know who is listening (just invoke it, if it is non-null). This is ideal as multiple operations can subscribe simultaneously - for example 3 separate controls observing (data-binding) to the same property on a view-model.

Any cases where the delegate is acting as function (in particular with a return value) is tricker, as you need to think how you will handle that - take the first? Last? Aggregate?

Marc Gravell
  • 927,783
  • 236
  • 2,422
  • 2,784
  • It seems that multicast delegates *should* return void by law. Adding more than one nonvoid function to a delegate should throw an Exception. My O'Reilly book says that the "last" function is the one whose return value is used, but that seems so useless and bug prone. – Mark Lakata Sep 27 '12 at 22:22
  • 1
    @MarkLakata if the caller wants all the individual returns, you can use GetInvocationList. Everything you mention could *also* apply to `ref`/`out` parameters, or to the state of mutable regular parameters between each call - it isn't just the return value that gets complicated here. Frankly I'm content with it "as is"... – Marc Gravell Sep 28 '12 at 05:31
  • @MarkLakata The C# Language Specification also says that the return value of a delegate invocation is the return value of the last method in the list. Quote: _If the delegate invocation includes output parameters or a return value, their final value will come from the invocation of the last delegate in the list._ – Jeppe Stig Nielsen Nov 12 '12 at 12:15
7

Events are a prime example for the usage of MulticastDelegates. So, probably without realizing it, you are using them every day.

Femaref
  • 58,195
  • 7
  • 126
  • 170