in reply to Inheritance problem: Not a HASH ref
You've already gotten some answers, but after reading your question, and seeing Corion's suggestion, it made me think a bit. So just for amusement, I cobbled something together. I'm not saying you should use it, it's more of an amusing experiment that might suggest to you other avenues to explore.
I've not used the AUTOLOAD feature often, but I find it interesting, so I thought I'd whip up an experiment that will handle the case you call out: where you want to subclass a thing not based on a hashref.
$ cat pm_autodelegate.pl #!env perl { # A package based on a reference to something other than a hash package a_scalar_thing; sub new { my $class = shift; my $a = 99; return bless \$a, $class; } sub a { return 42; } sub b { return $_[1]*5; } } { # A package that you want to augment without munging around in # it's innards package auto_delegate; sub new { my $class = shift; my $delegate = a_scalar_thing->new(); return bless { delegate=>$delegate }, $class; } sub a { return '*'; } sub c { return 'D'; } # auto_delegate doesn't do the expected action, so try to # delegate it to the original thing sub AUTOLOAD { my $self = shift; my $func = $auto_delegate::AUTOLOAD; $func =~ s/.*:://; if ($self->{delegate}->can($func)) { $self->{delegate}->$func(@_); } else { print "auto_delegate: Dunno how to '$func'\n"; } } # Since we have AUTOLOAD, we need DESTROY or we'll get a # 'Dunno how to' message. We explicitly delete the delegate to # ensure it's collected--probably unnecessary, but harmless sub DESTROY { delete $_[0]{delegate}; } # AUTOLOAD docs indicate that overriding can() is probably # also a good idea. I didn't bother for this experiment... } my $orig = a_scalar_thing->new(tense=>0); print "orig: a:", $orig->a(), ", b(10):", $orig->b(10), "\n"; my $dele = auto_delegate->new(tense=>99, loose=>0); print "dele: a:", $dele->a(), ", b(10):", $dele->b(10), ", c:", $dele- +>c(), "\n"; print "dele: unknown_func:", $dele->unknown_func(66), "\n"; Roboticus@Waubli ~ $ perl pm_autodelegate.pl orig: a:42, b(10):50 dele: a:*, b(10):50, c:D auto_delegate: Dunno how to 'unknown_func' dele: unknown_func:1
It works as it is, but if you wanted to use something like it, you'll want to improve it. For example, in the AUTOLOAD sub, I do a lookup every time we need to do something not provided by auto_delegate. Corions solution explicitly patches the symbol table so the method invocations are faster. You could patch it on demand for better performance, if you want. You would also want to review the relevent documentation (notably perlsub and perlobj), figure out how you want to handle calling the superclass methods when needed, test the heck out of it to make it bulletproof.
For your case, I prefer Corion's solution, but I really wanted to play with AUTOLOAD for a little bit this morning.
# I didn't test this, and didn't throw it away for some reason... package a_delegate; BEGIN { # If you don't like AUTOLOAD you could also use Corions solution, +but use a blacklist # instead of a whitelist, to ensure that you capture new superclas +s methods if any arise. my %IGNORE = map { $_=>undef } qw( new and other funcs to ignore d +elegation ); for my $method (keys %Furl::) { next if exists $IGNORE{$method}; die "a_delegate already provides an implementation of $method! +\n" if exists $a_delegate::{$method}; *$method = sub { my $self=shift; $self->{delegate}->$method(@_ +); }; } # Your normally scheduled package stuff... }
I hope you find this amusing.
...roboticus
When your only tool is a hammer, all problems look like your thumb.
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^2: Inheritance problem: Not a HASH ref
by bliako (Abbot) on Feb 26, 2019 at 13:44 UTC | |
by roboticus (Chancellor) on Feb 26, 2019 at 21:08 UTC | |
by bliako (Abbot) on Feb 26, 2019 at 21:29 UTC |