Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Methods, within a class, pass callbacks; how to deal with that in derived class?

by Anonymous Monk
on Oct 13, 2024 at 09:34 UTC ( [id://11162231]=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

use strict; use warnings; use feature 'say'; package Foo { sub new { my $pkg = shift; return bless {}, $pkg } sub frob { my $self = shift; $self-> foo( \&cb ) } sub blurt { my $self = shift; $self-> foo( 'cb' ) } sub foo { my ( $self, $cb ) = @_; $self-> $cb } sub cb { my $self = shift; say ref $self, ' ', __PACKAGE__ } }; package Bar { our @ISA = ( 'Foo' ); sub cb { my $self = shift; say ref $self, ' ', __PACKAGE__ } }; my $foo = Foo-> new; my $bar = Bar-> new; $foo-> frob; $bar-> frob; $foo-> blurt; $bar-> blurt;

It says (which doesn't require explanation, that's not the question):

Foo Foo Bar Foo Foo Foo Bar Bar

The callbacks in above classes look the same for the SSCCE, but let's pretend they are different, and I only want to change callback behaviour in derived class.

In practice, there are multiple changes, including some of the "callbacks". My class inherits from CAM::PDF, one of its "cornerstones" is the traverse method, which is called by a few specialized methods with a callback as an argument. e.g., verbatim, a short one:

sub setObjNum { my $self = shift; my $objnode = shift; my $objnum = shift; my $gennum = shift; $self->traverse(0, $objnode, \&_setObjNumCB, [$objnum, $gennum]); return; }
and relevant line in traverse is:
$self->$func($objnode, $funcdata);

Is calling a callback i.e. code reference as method on an instance the accepted and OK practice, to begin with? In derived class, I'm now in some mess of a situation.

Should I override every "specialized" method (even those I didn't intend to) and replace coderefs with strings? Will it hurt performance, and how much?

Maybe I can fix all that at the "central location" (i.e. traverse) without touching every "specialized method" -- to convert a coderef to sub name? How to do that using Perl built-in (or core) functions? Would this solution be better (faster, cleaner, etc.)?

Replies are listed 'Best First'.
Re: Methods, within a class, pass callbacks; how to deal with that in derived class?
by hv (Prior) on Oct 13, 2024 at 15:48 UTC

    Is calling a callback i.e. code reference as method on an instance the accepted and OK practice, to begin with?

    What it is doing is normal practice. I would say it is not calling it "as a method" - clearly there is no method lookup occurring here. The callback is documented (by comments) as a private function, and as such it is not expected to be overridden. In this case $self->$callback(...) is just a convenient alternative to $callback->($self, ...).

    Maybe you can explain more about what you are trying to do: how is your subclass of CAM::PDF intended to differ from the base class, and how does that affect what setObjNum should do?

    Depending on your intention, it is entirely possible that your class should implement its own setObjNum to do what it needs to do independently, either before or after calling the SUPER:: (or maybe NEXT::) method. Or you could wrap it with some variant of Moose to use one of its before, after, around keywords.

Re: Methods, within a class, pass callbacks; how to deal with that in derived class?
by karlgoethebier (Abbot) on Oct 14, 2024 at 07:16 UTC
Re: Methods, within a class, pass callbacks; how to deal with that in derived class?
by Anonymous Monk on Oct 13, 2024 at 13:32 UTC
    Will it hurt performance

    In fact, this concern is no longer relevant. As I have just checked myself, calling "traverse" with string vs. coderef as an argument results in average time for some operation rising to ~4.1 s from ~4.0 s for what serves me as "most internally complex PDF sample I'm testing against" in my zoo of files. That is not a problem at all; I'll override every original method which call "traverse", they are just a few, to eliminate a bug I stumbled upon and possible future traps. I'm still wondering if passing around "hard" callback coderefs, in OOP environment, was a good idea.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11162231]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (3)
As of 2025-01-24 15:56 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Which URL do you most often use to access this site?












    Results (68 votes). Check out past polls.