tag:blogger.com,1999:blog-2428374771421713311.post6218278789669344055..comments2024-03-10T12:04:17.661-07:00Comments on The Oracle at Delphi: Multicast Events - the cleanupAnonymoushttp://www.blogger.com/profile/10119008505905401707noreply@blogger.comBlogger6125tag:blogger.com,1999:blog-2428374771421713311.post-48940949549900078692008-09-30T06:04:16.000-07:002008-09-30T06:04:16.000-07:00A perfect example for multicast event is TApplicat...A perfect example for multicast event is TApplicationEvents or better this:<br><br>http://cc.codegear.com/Item.aspx?id=18199<br><br>It takes care of proper hooking and cleanup. I wrote it way back in Delphi 5. With generic multicast event it could be coded a bit more elegant. Though works perfectly as is.Robert Cernynoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-39962548699621230972008-08-25T13:21:31.000-07:002008-08-25T13:21:31.000-07:00"I still don’t see where the "heavy"..."I still don’t see where the "heavy" contract is in my implementation that you refer to. Sure, IOn_Destroy has a number of methods, but implementing that interface is trivial - it actually doesn’t require any "implementation" as such, as a plug-and-play implementation is provided for instant use via interface delegation."<br><br>I probably overstated "heavy", however from "no contract" to "any contract" is a leap. I also explained up front that the presumption of event source and sink are intended to be TComponent derived.<br><br>I was also showing how an existing, well established bit of internal machinery can be used to help enable brand new functionality. Rather than introducing some new pattern, I chose to leverage an existing one.<br><br>"That 20% where it’s "not so useful" (afaics, no use at all in fact) could become a recurring nightmare."<br><br>That is a rather strong assertion. One must certainly be very careful about its use, that's for sure, but "no use at all?" This "no use at all" version has been used successfully by the RAD Studio IDE since 1995 with little to no major faults or other problems. If you want to talk heavy contracts, that version certainly has it in spades ;-). There is a lot of work besides just manually creating a unique, typesafe descendant.<br><br>Finally, if I sounded like I was somehow minimizing or denigrating your work, I truly apologize. I would rather focus on the similarities in the approaches rather than the differences.<br><br>"By the same token, ime an event is either usefully multicast or steadfastly unicast, but this is a decision that a framework makes."<br><br>I think we can strongly agree on this one. In fact I said as much in my last post.<br><br>"I’ve not yet found a practical use for an adapter that transmogrifies a unicast event into a multicast one - it’s something that makes demos easier, but not something that (I’ve found) has use 'in the wild'."<br><br>Short of retrofitting large bits of the existing framework, providing some useful mechanism to do this still has some value. Given the luxury of starting from scratch, things may be different. However I don't have that advantage and need to take as pragmatic of an approach as possible.<br><br>"Clever it may be, but it looks horrible, imho and there is nothing about Button1.OnClick to tell you that you should do this and so prevent clobbering the 'adapter':"<br><br>Thank you for bringing this up! That is a point I certainly failed to make in this post. Once you go multicast, you can't go back ;-). As for the syntax, I also agree that it could be better, which is why I've added the Include/Exclude methods:<br><br> class procedure Include<T>(const AEvent, AMethod: T); static;<br> class procedure Exclude<T>(const AEvent, AMethod: T); static;<br><br>Thanks for taking the time to comment.<br><br>Allen.Allen Bauernoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-39350177565553536472008-08-25T04:11:39.000-07:002008-08-25T04:11:39.000-07:00You touched on something with regards to events in...You touched on something with regards to events in a Garbage Collected environment. One dangerous thing that all .NET developers should know is that event handlers are not automatically garbage collected. You MUST manually unhook the event handler in the consumer class, or assign the event to null in Dispose method of the provider class (and the consumer must of course call Dispose). Otherwise you can have major memory leaks! In short, all events must be manually cleaned up in .NET.Lee Grissomnoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-65846362588688879992008-08-25T05:15:36.000-07:002008-08-25T05:15:36.000-07:00Lee, That is true in certain scenarios, however f...Lee,<br><br> That is true in certain scenarios, however for a given grouping of object instances with various references events and handlers, the whole grouping will be collected once none of the objects are deemed as no longer being rooted. Always manually unhooking events is not a hard-and-fast rule.<br><br>Allen.Allen Bauerhttp://blogs.codegear.com/abauer/noreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-9931237883583655072008-08-25T10:59:20.000-07:002008-08-25T10:59:20.000-07:00Hmmm, whilst the 80/20 rule is often a good thumb-...Hmmm, whilst the 80/20 rule is often a good thumb-rule, in this case I'm not so sure.<br><br>That 20% where it's "not so useful" (afaics, no use at all in fact) could become a recurring nightmare. <br><br>"once we’ve established this solution ... no longer worry about this cleanup"<br><br>If I understand your intent correctly this is only going to be true if your listeners all derive from TComponent. Otherwise you absolutely do still have to worry about cleanup (and keep an eye on your base classes ultimate ancestors to determine whether you need to worry - that's two worries).<br><br>;)<br><br>Surely an approach with a consistent approach has to be better?<br><br>I still don't see where the "heavy" contract is in my implementation that you refer to. Sure, IOn_Destroy has a number of methods, but implementing that interface is trivial - it actually doesn't require any "implementation" as such, as a plug-and-play implementation is provided for instant use via interface delegation.<br><br>It's even an approach that can be adapted to fir your preferred model. If this interface were introduced on TComponent you would get your TComponent coverage AND still have a mechanism that didn't *rely* on TComponent.<br><br>(for example, I'd go further than your TComponent assertion, and suggest that most listeners are implemented by TForms. My Deltics.Forms TForm class - http://www.deltics.co.nz/blog/?p=222 - implements IOn_Destroy so I never need to worry about even cleanup in my forms)<br><br><br>A lot of listeners WILL be TComponent derived (i.e. GUI) classes. But one of the benefits of multicast events is that listeners within a framework are able to use the same notification mechanisms that framework consumers use.<br><br>By the same token, ime an event is either usefully multicast or steadfastly unicast, but this is a decision that a framework makes. I've not yet found a practical use for an adapter that transmogrifies a unicast event into a multicast one - it's something that makes demos easier, but not something that (I've found) has use "in the wild".<br><br><br>I also really don't like the "user" code that comes out of this approach:<br><br>TMulticastEvent.MulticastEvent(Button1.OnClick).Add(Button1Click);<br><br>Clever it may be, but it looks horrible, imho and there is nothing about Button1.OnClick to tell you that you should do this and so prevent clobbering the "adapter":<br><br> Button1.OnClick := Button1Click; // Bye-bye multicast!<br><br><br>All very interesting stuff though.Jolyon Smithhttp://www.deltics.co.nznoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-67120367452542861302010-04-18T17:17:12.000-07:002010-04-18T17:17:12.000-07:00Is there any chance of explaining the class proced...Is there any chance of explaining the class procedures Include and Exclude? Which class is this attached to and what do they do? <br><br>Maybe I'm missing something but I can't figure out how you "fish out" the MulticastEvent instance from the method pointer for the class function MulticastEvent. Will you be releasing any code for these classes?Colin Jnoreply@blogger.com