Re: method aliases with goto(&NAME)
by tobyink (Canon) on Sep 17, 2013 at 11:32 UTC
|
package Parent {
sub legacy_method {
my ($self, @args) = @_;
return $self->current_method(@args);
}
sub current_method {
return 1;
}
}
package Child {
use base 'Parent';
sub current_method {
return 2;
}
}
Child->legacy_method; # returns 2
If you swap in your goto implementation of the legacy method, then calling Child->legacy_method returns 1.
Here's an alternative safer version using goto...
sub legacy_method {
my $next = $_[0]->can('current_method');
goto $next;
}
See also http://tvtropes.org/pmwiki/pmwiki.php/Main/ThinkOfTheChildren.
use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
> If you swap in your goto implementation of the legacy method, then calling Child->legacy_method returns 1.
Don't you think this could perfectly be the intended behavior, since Child doesn't seem to have any legacy_method?
But your right that the OP was wrong about the equivalence.
Cheers Rolf
( addicted to the Perl Programming Language)
| [reply] [Watch: Dir/Any] [d/l] |
|
There are probably instances where you'd want two methods that behave identically in the parent class, but behave differently in the child class. However, given that the title of this thread mentioned "method aliases", I'm assuming the intention is that legacy_method acts as an alias (i.e. behaves identically) for current_method, unless a child class explicitly overrides legacy_method to make it behave differently.
use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
|
| [reply] [Watch: Dir/Any] |
Re: method aliases with goto(&NAME)
by Anonymous Monk on Sep 17, 2013 at 10:57 UTC
|
ask if anyone sees any drawback to this approach. There are none except in the name -- goto -- kinda like "eval" -- scary for the scaredy
OTOH *oldname = *newname;
| [reply] [Watch: Dir/Any] |
|
sub legacy_code {
warn ("This method is deprecated, use current_method instead");
goto(¤t_method);
}
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: method aliases with goto(&NAME)
by ikegami (Patriarch) on Sep 18, 2013 at 19:24 UTC
|
What are your motivations?
Modify the stack to pretend `legacy_method` wasn't called is surely detrimental. You could avoid that (and speed things up an itsy bit) with the following:
sub legacy_method {
¤t_method;
}
But both the above and your approach fail when a child class overrides current_method. I'd use the following:
sub legacy_method {
my $self = shift;
$self->current_method(@_);
}
(Which actually works and avoids needless copying unlike the code you presented as the baseline.) | [reply] [Watch: Dir/Any] [d/l] [select] |
Re: method aliases with goto(&NAME)
by manorhce (Beadle) on Sep 17, 2013 at 11:07 UTC
|
| [reply] [Watch: Dir/Any] |
Re: method aliases with goto(&NAME)
by zork42 (Monk) on Sep 18, 2013 at 08:50 UTC
|
| [reply] [Watch: Dir/Any] |
Re: method aliases with goto(&NAME)
by sundialsvc4 (Abbot) on Sep 17, 2013 at 12:41 UTC
|
“Scary” is the ultimate under-statement. “Unmaintainable” is its second cousin.
You probably have a short-list of possibilities where this code can actually “go to.” Put this into the code such that it cannot go anywhere else without dieing. For example, return a string or a constant, then use a if {goto} elsif {goto} else {die} construct. It still sucks but it sucks slightly less. Now, you do not have to “look somewhere far-away to see what it is supposed to be doing, then cross-your-fingers to see if it actually does it.” That’s exactly the sort of thing that causes pagers to go-off at 3AM.
| [reply] [Watch: Dir/Any] |
|
goto(¤t_method);
... does. It doesn't execute ¤t_method, and then go to whatever label was returned from ¤t_method. It just goes to ¤t_method. It's not scary; it's not unmaintainable; it's just a tail call.
From perlfunc (my emphasis):
The goto-&NAME form is quite different from the other forms
of goto. In fact, it isn't a goto in the normal sense at
all, and doesn't have the stigma associated with other gotos.
Instead, it exits the current subroutine (losing any changes
set by local()) and immediately calls in its place the named
subroutine using the current value of @_. This is used by
AUTOLOAD subroutines that wish to load another subroutine and
then pretend that the other subroutine had been called in the
first place (except that any modifications to @_ in the current
subroutine are propagated to the other subroutine.) After the
goto, not even caller will be able to tell that this
routine was called first.
use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
| [reply] [Watch: Dir/Any] |