[Mono-list] Re: [Mono-bugs] Hi.

Daniel Stodden stodden@in.tum.de
12 Jul 2002 00:34:53 +0200

On Thu, 2002-07-11 at 09:11, Nick Drochak wrote:
> | -----Original Message-----
> | From: mono-list-admin@ximian.com [mailto:mono-list-admin@ximian.com]On
> | Behalf Of Dietmar Maurer
> | Sent: Thursday, July 11, 2002 3:22 PM
> |
> | On Thu, 2002-07-11 at 06:52, Yuan-Fen Eric Kuo || 郭源汾 wrote:
> | > I am new to the thread so please forgive me if it has been 
> | discussed or I
> | > have missed some points somewhere.
> | > 
> | > It seems that delegate invokes the methods in the reversed order as they
> | > were combined. According to MS's Spec.  isn't it supposed to 
> | invoke methods
> | > from the left to right of the operator?
> | 
> | Yes, I think we should not reverse the order. Do you have some tests to
> | show that behavior? 
> I just read in a few of places over the past couple of days that the order is not guaranteed and one should not depend on it.
> Does someone have information otherwise?

i can assure you the order should be guaranteed, the same order in which
the individual combination of addition/removal suggests. 
just what one would expect.

same goes for MS. the documentation remains comparably precise in this
respect, once you've sorted out the blurry stuff (the MS class design
isn't all that well).

haven't looked again into it for quite some time now. though, i can't
replicate above problem just by trying from simple examples.

maybe the original question derived from browsing the source code?
mono keeps multicastdelegate chains linked in a recursive manner, i.e.
each multicastdelegate simply keeps a single link to another one or null
(as opposed to encapsulated arraylists or whatever).
the internal chaining is indeed _reverted_. i.e. the internal link is a
prev-pointer, not a next pointer.

why? removal. consider removing an invocation chain from another. now
the fun part is that not the first occurence of the list to remove is
removed but the _last_ occurence.

might have originated at MS from a side effect. but it's documented in
the class docs nonetheless.
removals are therefore implemented in mono by reverting the internal
order for speed. ::Invoke() then recurses depth-first through the chain,
which gets you back to the expected order during invocation. eats up
some stack space, but i can't think of a more elegant way.

summary, for a bundle of delegates of type foo(int):

(a + b + c)(42) invokes a -> b -> c.

(a + b + c - b)(42) invokes a -> c.

(a + b + c + a + b - (a + b))(42) 
invokes a -> b -> c, not c -> a -> b.


i've spent quite some time until i got this right. pleaso drop me a note
if any problems arise. i remember having checked in unit tests for this,