bsb has asked for the wisdom of the Perl Monks concerning the following question:
The system uses hash-based objects which can have CODE ref entries which are run to provide per-object behaviour. It has single inheritence so 'super' is not too complicated. I hope the intent is clear without all the entire class.
The ideal solution would have 'super' know which code ref called it and then find the next in the object_can_all list. Next best would be a syntactic improvement to make the second form below easier. Ideas? Suggestions?
=item super Call the prototype's/parent's version of a function. This is tricky because the when coding the $self->super call intends to target one thing but a subclass of this will provide a different $self that has the original as it's prototype. So super needs to discover when this has happened, seemingly impossible using just caller($n) and $self. More information is needed from 'new' time. That's why there's two interface variants: $self->super(check => @_); This asserts that there are only two "check" routines in the prototype chain for $self and it calls the last one (which assumes that only the first/sub-object uses super). The second variant requires a more complex declaration, permitting more than two subs in a hierarchy. You must pass super a coderef to the surrounding code so that it can find it in the list of potential versions. use WeakRef; my $this_sub; $this_sub = sub { my $self = shift; $self->super($this_sub, check => @_); } $object->{check} = $this_sub; weaken $this_sub; The weaken is important to avoid a circular reference as the closure captures $start_code_ref. This interface division means that objects must use the second form if they want to their sub-objects to be able to override a method using super. Requiring adjustments to the parent is ugly but seems to be the only solution. Devel::Caller provides caller_cx which would help but it is seems flak +y. =cut sub super { if(ref $_[1] ne 'CODE') { # No code ref, super must be unambiguous my ($self, $attr) = (shift, shift); # Find all versions of $attr for this object my @subs = $self->object_can_all($attr); die "Ambiguous super call for $attr on $self" if @subs != 2; # Super must be intended for the second (ie. last) one my $super_sub = pop @subs; return $self->$super_sub(@_); } else { # They gave us a reference to the intended start sub my ($self, $this_sub, $attr) = (shift, shift, shift); # Find where $this_sub is my @subs = $self->object_can_all($attr); my $n = 0; while ($subs[$n] != $this_sub) { $n++ } # Run the next highest one die "No super for $attr on $self" unless exists $subs[$n+1]; my $super_sub = $subs[$n+1]; return $self->$super_sub(@_); } }
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Sub getting it's own CODE ref? Proto-OO
by hv (Prior) on Jun 15, 2004 at 11:31 UTC | |
by bsb (Priest) on Jun 17, 2004 at 01:16 UTC | |
|
•Re: Sub getting it's own CODE ref? Proto-OO
by merlyn (Sage) on Jun 15, 2004 at 15:17 UTC | |
by bsb (Priest) on Jun 17, 2004 at 01:17 UTC |