in reply to RFC: Class::DispatchToAll
-- Randal L. Schwartz, Perl hacker
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: •Re: RFC: Class::DispatchToAll
by TheDamian (Vicar) on Jul 11, 2002 at 04:23 UTC | |
If both Mother and Father have DESTROY methods, what happens? Under normal Perl semantics, only Mother::DESTROY would be called, since it's the left-most, depth-first method encountered during the dispatch. But failing to call one (or more) of an object's inherited destructors is not correct behaviour. Hence the need to be able to call all of them:
| [reply] [d/l] [select] |
by dws (Chancellor) on Jul 11, 2002 at 06:03 UTC | |
Uh, oh. Multiple Inheritance. A couple of years of doing Smalltalk (which didn't have multiple inheritance, but which let you fake interface interitance via mixins), and a couple of years of Java and C++ have lead me to believe that Multiple Inheritance is a Very Risky Thing, and that it can always be worked around by either composition or reducing to inheriting from one data-bearing class and multiple (data-less) interface classes. Doing so avoids the multiple destructor problem. Perhaps you've run into a situation where multiple inheritance is the right thing to do. If so, I'd like to hear about it.
| [reply] |
by Abigail-II (Bishop) on Jul 11, 2002 at 11:07 UTC | |
Some problems LPC has with multiple inheritance aren't found in Perl (for instance, the possibility of duplicating variables when a class is inherited by two paths - different implementations of LPC solve it differently). Other things are solved differently, for instance, one flavour of LPC forbids inheriting from two classes if they have methods with the same name - unless the inheriting class defines a method with that same name. There is nothing wrong with multiple inheritance. It's just hard to implement is right, which is way some languages take the easy way out and outright forbid it. Inheritance is already a hard problem in Perl, but multiple inheritance is a real nightmare. But that's the fault of Perl, not of multiple inheritance. Abigail | [reply] |
by merlyn (Sage) on Jul 11, 2002 at 15:22 UTC | |
So I still haven't seen a place where calling all of the methods blindly is useful or maintainable. | [reply] |
Re: ?Re: RFC: Class::DispatchToAll
by domm (Chaplain) on Jul 11, 2002 at 08:19 UTC | |
App | App::Basic / \ App::Basic::Special1 App::Basic::Special2 | | | | | My::App | | / \ | My::App::Special1 My::App::Special2Note that My::App doesn't inherit from App. And note that there are My::OtherApp, Your::App too, looking like My::App and inheriting from App::* Each of this Classes contains some config values as Class Data. I want to be able to fetch all those config values, merge them and do something with the result.
E.g.: Say, each class contains an array called @order and a hash called %lables.
Each Class now defines some of those values. Some Classes append new values to @order and %lables, some overwrite data in %lables. There are some basic fields (used everywhere in the app) defined in App::Basic. Each App::Basic::Special1/2 adds some fields unique to this special case. Now, My::App changes some field lables (e.g. use another language). My::App::Special1 may add even more fields that are only needed in My::App (there might be a My::OtherApp::Special1 that inherits from App::Basic::Special1 and doesn't use this fields) Then I call dispatch_to_all('get_fields') which fetches all those @field arrays, massage the returned array of all return values to fit my needs, and voila: I get the array of fields used by this Class, without having to specify the "Basic" fields in all Subclasses (which would result in a lot of typing and and even bigger lot of problems should I need to change a App::Basic config value) This was/is my problem, and that's why I wrote Class::DispatchToAll, which seems the best way to solve this problem to me. But if you now another way, please let me know...
| [reply] [d/l] [select] |
by merlyn (Sage) on Jul 11, 2002 at 15:31 UTC | |
Then I call dispatch_to_all('get_fields')This is where I lost you. If a class has a get_fields, I'd expect it to return all appropriate fields. If it has overridden a base class method of the same name, then there's a reason for that, so it should either call all the immediate base class methods and derive an appropriate response from that, or simply ignore those and riffle through it's own data to produce the result. Perhaps you don't get why "extending" and "overriding" are useful. You are breaking that model. At that point, don't call it OO programming any more. You are merely aggregating through hierarchies, turning "IS A" into "HAS A" relationships. This will scare every single maintenance programmer that has to look at your code. Please don't do that. All the studies show that most of corporate software money is spent on maintaining, not creating, the software. You have just spent a whole lot more money than you even imagine. | [reply] |
by domm (Chaplain) on Jul 11, 2002 at 20:19 UTC | |
I do not want to write 100 accessor methods in each and every class, telling all those methods where to look for the data. Instead, I have one general accessor (get_config) in App. Through normal Perl inheritance, every class can access it. So, how can this one general method know which values to return? Is there a "standard" way to do this? Or is my architecture completly screwd? Perhaps you don't get why "extending" and "overriding" are useful. I know Perl OO quite well. Overriding is completly clear to me, but what do you mean by "extending"? Something like
You are breaking that model. I know. I break it by intention, because it doesn't fit my needs. And as TheDamian is doing something similar (NEXT.pm), it seems that I am not the only one with that need... At that point, don't call it OO programming any more. You are merely aggregating through hierarchies, turning "IS A" into "HAS A" relationships. I am a so-called "accidental programmer" (i.e. I didn't learn programming at university), and while I am quite aware of OO-methodology, I cannot tell whether this is still OO or not. This will scare every single maintenance programmer that has to look at your code. Please don't do that Currently, I am maintaining an old version of this App (written by me, so it's my fault...). In the old version, all those fields are specied in there own class. I can tell you from hourlong search-and-replace-sessions that it this is quite a pain to maintain, as I have to wade to a lot of config files and change/add some values, if I change something in the whole App. It would seem much clearer to me if each class only adds its specif stuff (or changes already defines stuff). This is what I hope to accomplish with Class::DispatchToAll.
| [reply] [d/l] [select] |
Re: ?Re: RFC: Class::DispatchToAll
by frag (Hermit) on Jul 11, 2002 at 04:44 UTC | |
The problem can be stated like this: say you want a object to try to get_money(). Say the object is a member of the classes Executive::Enron, Citizen::American and Human::AbleBodied. So you try $KenLay->get_money();. It so happens that Executive::Enron::get_money() will return a failure. However, method dispatch stops at this failure, without trying the methods in other classes. For the sake of argument, we'll call this a bad thing. (I'm speaking highly rhetorically here, ok? For a non-dark side example, consider object $YAPC, member of classes Herd::Camels and NonProfit::OfficiallyLicensed. Herd::Camels::get_money() contains 'goto &pass_hat;' but NonProfit::OfficialyLicensed::get_money() writes grant proposals.) You can create wrapper methods or a dispatch table to explicitly call each fully-qualifed method in order, but that would be unusably brittle. You could use NEXT, but if the modules you're dealing with already exist, you'd have to rewrite all the modules (or at least the methods, in new subclasses) from the heirarchy that you are working with. Thanks to the things I learned from Damian's Advanced Objects course (another satisfied customer!), I was able to devise a solution. But it wasn't particularly easy, and can't be simply carried over to other modules. I was just wondering if this sort of thing could be done in a portable fashion when I saw this. Thanks, domm! -- Frag.
| [reply] [d/l] |
by merlyn (Sage) on Jul 11, 2002 at 15:26 UTC | |
Why would you be passing control from your derived method to a base method that might fail? You should be calling it directly, taking the results (or none), then deciding whether or not to call the next. Again, when you inherited from the multiple base classes, it's your responsibility to decide how to handle the multiple dispatch. And that's what NEXT is for. | [reply] |
by frag (Hermit) on Jul 12, 2002 at 05:08 UTC | |
Note that I misspoke in my earlier comment about wrapper methods; essentially, that's all this is, dispatch being controlled and monitored by a single method. You've got a generic wrapper method in the child class that takes the names of the parental methods that it should handle. This does not vary at run-time, but is a constant within the child class that is handling the dispatch. Also please note that I am not arguing that multiple inheritance is some sort of no-brainer to be used cavalierly. I am saying that I have found a particular situation where I think it makes sense. I don't question that this is a single solution to a limited set of problems. Finally, I have to admit that I just don't see that NEXT is always the best approach. NEXT allows each method in the parent class to make its own decisions about whether to continue dispatch or not. But it seems more natural to me, and safer, even, to have a central method oversee the process. -- Frag.
| [reply] |