Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

dynamic method creation, dispatch table or pseudo methods?

by Discipulus (Abbot)
on Apr 18, 2021 at 19:22 UTC ( #11131437=perlquestion: print w/replies, xml ) Need Help??

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

Hello folks,

I'm planning a little module ( an interactive cli using Term::ReadLine ) but I want make possible for the module user to add some method in the constructor, no Moo* usage is planned so I'd like to see basic perl approaches. At the moment I have soemthing like:

sub new{ my $class = shift; my %opts = @_; unless ( defined $opts{dumper} ){ require Data::Dumper; # + () to avoid Name "Data::Dumper::Dumper" used only +once: possible typo at # full qualified name to avoid runtime error $opts{dumper} = sub{ print +Data::Dumper::Dumper(\$_[0 +]) } } return bless { %opts }, $class; }

dynamic method creation

I can build up a method dynamically with *{"${class}::${meth}"} = sub { my $self = shift; ... } I imagine I can do this directly in the new constructor, right? There are drawbacks or pitfall I overlooked in this approach?

dispatch table

The above code for new adds not a method but a property of the object actually being a callable sub: after I can access it like in  $obj->{dumper}->([1,2,{a=>42}])

I can expand this providing to the module user a method to add commends: use Data::Dump; $obj->add_command( {descr=>'a dumper', command => sub{ dd $_[0] } )

This seems to me a simpler approach and I cant imagine drawbacks using it. The only one I can imagine is that not being a method I cannot have $self available inside this calls (even if I dont know atm if will be needed).

pseudo methods?

But I can craft execute_command to pass $self as first argument:

sub execute_command{ my $self = shift; my $wanted_command = shift; my @whole_data = @_; $self->{ $wanted_command }->( $self, @whole_data ); }

This leads to something like a pseudo method; is this too dirty? Has other drawbacks? Do you expulse me from perlmonks if I write it down? :)

In addition: if new will be as above in the final module, should I add Data::Dumper to prerequisites? I'd say yes but... if not Data::Dumper but Math::Mersenne::Primes was the case? I must add it to prerequisites even if there is the chance it will be never loaded?

L*

There are no rules, there are no thumbs..
Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

Replies are listed 'Best First'.
Re: dynamic method creation, dispatch table or pseudo methods?
by choroba (Archbishop) on Apr 18, 2021 at 19:56 UTC
    Another possibility would be to create an abstract class with
    sub dumper { die 'Dumper not defined in the abstract class!' }
    then subclass it with MyClass::Dumper where you override the sub:
    use Data::Dumper; sub dumper { my ($self, @data) = @_; print Data::Dumper::Dumper(@data); }
    If the user wants to use a different Dumper, they can subclass the abstract class with a different implementation of the dumper.
    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: dynamic method creation, dispatch table or pseudo methods?
by LanX (Sage) on Apr 18, 2021 at 20:33 UTC
    If providing implementation is part of the API, you might want to have better control about user errors

    you could do something like (untested)

    sub my_meth { my $self = shift; my $cmd = $self->{api_meth}; unless ( defined $cmd ) { # default } else { eval { $cmd->(@_) } or raise_error(); } }
    Of course this will be slower than your suggestions...

    TIMTOWTDI and YMMV :)

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

Re: dynamic method creation, dispatch table or pseudo methods?
by perlfan (Vicar) on Apr 19, 2021 at 00:51 UTC
    > should I add Some::Mod to prerequisites

    Since you're using require, this would not effect any installation process. But it'll be a run time error. So if you wish to be "kind" to your users, then yes you should add it. If there is a core feature set you can provide and put any of the commands that will never be loaded into extension modules. And in those, make sure you have full coverage of the modules needed.

    As for the first part of your question, if you got something work it, go for it. I will say, the whole time I was reading this I kept thinking App::Cmd. I cast no judgement personally regarding the various ways Perl allows for the dynamic creation of subs. I've used only a fraction in my day, but always enjoy seeing the options laid out. However, I will answer the question with a question: do you really need to allow users to define custom commands in that way? It seems like you're looking for a perl REPL/shell - and I think a few options exist. So your question may come down to - which one to use and how do I want to extend it to provide custom commands.

Re: dynamic method creation, dispatch table or pseudo methods?
by Discipulus (Abbot) on Apr 20, 2021 at 20:33 UTC
    hello,

    thanks for the suggestions, even if I really got no answers :)

    I received, from another source I consider affordable, if not authoritative, the confirmation that what I called pseudo-method is a perfectly viable design. They called it dispatch table for a known invocant and they told me I can also write them as: my $code = $self->{$wanted_command}; $self->$code(@whole_data) to appears similar to a real method call. Personally I prefere my first syntax as I find it more explicit.

    Added for the posterity.

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (4)
As of 2021-10-28 09:28 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    My first memorable Perl project was:







    Results (96 votes). Check out past polls.

    Notices?