From: Everett, T. <TEv...@AL...> - 2002-09-04 21:53:10
|
-----Original Message----- From: Scott Lanning [mailto:sla...@th...] Sent: Tuesday, September 03, 2002 11:38 PM To: Everett, Toby Cc: 'wxp...@li...' Subject: Re: [wxperl-users] Patterns, anyone? > On Tue, 3 Sep 2002, Everett, Toby wrote: > [...] > > My next goal was to use anonymous subroutines as much as possible. > > I think a problem with that is if your interface does > the same thing from several different places -- toolbar, > menubar, treectrl -- then you duplicate code. > Plus I think nesting anonymous subroutines is ugly, > but that's just me. :) I agree that when your interface does the same thing from multiple places that it is a Good Thing(TM) to factor the code. I usually end up with an anonymous subroutine wrapper rather than simply referencing the class method, though. Ahhh!!! The light just blinded me. I know why EVT_* requires you to pass $self. So it knows upon what object to call the subroutine - otherwise the called subroutine wouldn't have access to $self. Basically, you can think of there being two coding paradigms that were available when the EVT_* syntax was written: one in which EVT_* would be responsible for building the closure and one in which the user would buildsthe closure. Here's two ways that that EVT_* could have been written: EVT_BUTTON($self, $button, \&method); EVT_BUTTON($button, sub {$self->method(@_)}); In the first one, the tri-value syntax EVT_BUTTON guarantees the passed subroutine will be called with $self and $event. In the second one, the bi-value syntax EVT_BUTTON only guarantees that the passed subroutine will be called with $event. If the passed subroutine needs access to $self, you have to create a closure and package $self into it. The first approach to EVT_BUTTON encourages methods as handlers, whereas the second has a strong tendency to favor closures. Here's something interesting to think about, though. The "normal" EVT_BUTTON syntax I see in use everywhere inhibits subclassing. Let's say that you have a MyFrame class that creates a button and then defines the method OnButton to handle that button click. The normal code in that situation would be: EVT_BUTTON($self, $button, \&OnButton); That works fine until you create MyFrame_SubClass, a subclass of the MyFrame class, and try to override the OnButton method _without_ overriding the code that calls EVT_BUTTON. In that situation, because the code that calls EVT_BUTTON is executing in the MyFrame package, \&OnButton is a reference to the MyFrame::OnButton subroutine. Even though $self is of class MyFrame_SubClass, EVT_BUTTON is going to call $self->$coderef($event), where $coderef is equivalent to MyFrame::OnButton. Which means that MyFrame_SubClass::OnButton gets ignored. On the other hand, things work if you use a closure like so: EVT_BUTTON($self, $button, sub {$self->OnButton($_[1])}); or, more correctly (in case for whatever reason there are multiple parameters beyond $self): EVT_BUTTON($self, $button, sub {(shift)->OnButton(@_)}); In that situation, because the matching of the OnButton method name to the implementing subroutine is delayed until the closure is executed, you ensure the method can be overridden easily. Of course, I could be completely wrong in my analysis above, but I'm reasonably certain I'm not. Although I haven't tested the above theory, when I co-wrote Class::Prototyped, I ended up learning more about the guts of the Perl OO stuff than I think really wanted to know. I'm not looking forward to tracking down the problems 5.8.x is bringing - the test cases are failing, and I need to sit down for a weekend and model 5.8.x's behavior well enough to get it working again :(. --Toby Everett |