ryo0ka has asked for the wisdom of the Perl Monks concerning the following question:
Hi Monks,
I want the following code to print out 'son', but it prints out 'parent':
my $obj = Son->new; print $obj->call; package Parent; sub call {char()} sub char {'parent'} package Son; use base 'Parent'; sub new {return bless {}, 'Parent'}; sub char {'son'}
How do you make my dream come true, without putting 'call' subroutine in 'Son' package newly?
Thank you!
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: How to do this?
by kcott (Archbishop) on Jun 22, 2013 at 02:05 UTC | |
G'day ryo0ka, Your main problem here is that you're ignoring the first argument passed to the class method new() (i.e. Son) and the first argument passed to the object method call() (i.e. $obj). A secondary problem is that the constructor, new(), should probably be in the Parent class. Here's a rewrite of your code to demonstrate this:
Additional example: While it's absolutely fine that you've posted minimal code to show your problem, it occurred to me that the following might be closer to what you were trying to achieve.
Note that there is no longer any hard-coded "parent" or "son" strings and that the Son class now has no methods at all; this code now relies entirely on inheritance to return the same information you had previously with two hard-coded char() methods. See how easy it is to extend the class hierarchy without needing to write a custom char() method for every new subclass:
-- Ken | [reply] [d/l] [select] |
by ryo0ka (Novice) on Jun 22, 2013 at 18:25 UTC | |
| [reply] |
Re: How to do this?
by rjt (Curate) on Jun 22, 2013 at 23:17 UTC | |
To unlock considerably more power in object-oriented applications, as well as dissolving some of the lumps in Perl's syntactic sugar, you may want to check out the very popular Moose (available on CPAN). With Moose, your example can be written succinctly as follows:
Output:
You'll notice that I didn't have to explicitly create any constructors, nor did I have to monkey with any of the unintuitive bless machinations normally required to instantiate objects and work with subclasses. I would probably take this a step further with a couple more features of Moose to turn the char() method into a proper class attribute:
On the surface, this doesn't change much: the output is the same, and thanks to init arg => undef and is => 'ro', its value is immutable just like the original char() method. However, rather than fetch and convert its reference type to lowercase every time it's called, the builder sub only fetches the result once, when the object is instantiated. For this example, the savings are small, but for more computationally expensive things, it will be significant. Perhaps more importantly, do not underestimate the expressive power of the has syntax; this makes it very clear what char does and what its limitations are. I'm by no means a Moose evangelist (Moosevangelist?), but for someone learning Perl OO for the first time, I see no particularly compelling reason to learn the hard way. Over time, sure, you will pick up the knowledge of what's going on under the hood, but most of the time, you just don't need to bother. If you're willing to put up with a many more module dependencies (around 50!), MooseX::Declare gives you even more syntactic sugar. The class definitions become:
How far you go should depend on the complexity of your object taxonomy. | [reply] [d/l] [select] |
Re: How to do this?
by sundialsvc4 (Abbot) on Jun 22, 2013 at 22:39 UTC | |
Ex minimis, in your code you are saying that Son is aParent ... hence, the object that it (incorrectly ...) produces will never search for its methods in Son, even though the constructor method is defined there. The search for classes will instead look in Parent, as you see it doing. Constructors in Perl are, as previously noted, told what class-name to use. A little crazy, but you do get used to it. | [reply] |