Use of multicast in C# multicast delegates
Asked Answered
J

2

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.

Jonahjonas answered 9/6, 2011 at 18:33 Comment(13)
I long for a day when I can forget about the multicastiness of delegates.Heterochromosome
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?Jonahjonas
@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.Heterochromosome
Then again, MulticastDelegate stores the delegate targets in a list :)Turbo
@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)Ozan
@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.Heterochromosome
@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?Stalinabad
@Stalinabad 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).Ozan
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.Ozan
@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 traversalOzan
@Stalinabad "which result should be returned?" See the comments to the answer by Marc Gravell.Yod
@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.Stalinabad
@Stalinabad 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.Yod
L
9

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 a function (in particular with a return value) is trickier, as you need to think about how you will handle that - take the first? Last? Aggregate?

Lilias answered 9/6, 2011 at 18:38 Comment(3)
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.Mirthless
@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"...Lilias
@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.Yod
A
7

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

Aleras answered 9/6, 2011 at 18:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.