Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

method dispatch question

by rovf (Priest)
on Jul 09, 2008 at 11:42 UTC ( [id://696428]=perlquestion: print w/replies, xml ) Need Help??

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

Sorry to come up again with a question, in particular one which I feel should be trivial (but I still don't see how to do it):

Assume I'm inside the method mymethod of the class below,

package MyClass; sub new { ... } sub f { ... } sub g { ... } sub h { ... } sub mymethod { my ($self, $mref)=@_; # Assume $mref is one of \&f, \&g or \&h ... }
and I would like to call the method which $mref refers to. Of course if I would, say, want to call method f unconditionally, I would simply write $self->f, but now we have the reference to the sub instead. My first attempt to write this was
$self->&{ $mref }()
but this gave a syntax error (why?). The second attempt was more successful: Writing
$mref->($self)
worked. Nevertheless, I have the feeling that there must exist some way to write this call, while still keeping the $self->notion. Any ideas?

-- 
Ronald Fischer <ynnor@mm.st>

Replies are listed 'Best First'.
Re: method dispatch question
by parv (Parson) on Jul 09, 2008 at 11:53 UTC

    You missed $self->$mref( ... ).

      Indeed, I missed it, and it works very well. But now let us make the problem a bit more complicated (I see that I have simplified to much from my original problem): Assume that $mref does not come in as parameter, but will be calculated somehow; for example:

      my $mref=$self->get_mref(...); # Calculate $mref $self->$mref(...); # use it to dispatch
      Can this still be written in one line, without intermediate variable $mref? I learned that my original id
      $self->&{ $self->get_mref(...) }()
      does not work, but extending your suggestion to this case would, I think, fail too:
      $self->($self->get_mref(...))()
      Can this (now more complicated) example be easily solved too?

      -- 
      Ronald Fischer <ynnor@mm.st>
        Even if there is a solution for that (and I don't doubt there is one, perl is full of surprising syntax ;-), you shouldn't go for it, because it's not really readable anymore.

        Use a temporary variable instead.

        $self->($self->get_mref(...))() won't work because $something->(...) treats $something as a sub ref. If there's a way, I suspect it involves ${...}.

        Can this still be written in one line, without intermediate variable $mref?
        $self->get_mref->($self, @args);

        or make get_mref return a code reference that captured $self so you can omit it when calling it.

        sub get_mref { my ($self) = @_; my $coderef = \&some_method; return sub { $self->$coderef(@_) }; } $self->get_mref->(@args);
        There is a way:
        use strict; use CGI; sub meth {'p'} my $cgi = CGI->new; print $cgi->${\meth()}('foo')."\n";
        but why would you want to do that?

        update D'oh! didn't read the question closely enough. This is not what you're looking for.

Re: method dispatch question
by moritz (Cardinal) on Jul 09, 2008 at 12:06 UTC
    The usual way to take a reference to method is to enclose the object in a closure:
    my $mref = sub { $obj->method(@_) }; # and then later: $mref->(@stuff); # (no $self here at all)
Re: method dispatch question
by polettix (Vicar) on Jul 09, 2008 at 16:10 UTC
    Once you have a reference to a method, the following notations are perfectly equivalent:
    $mref->($self); # OR $self->$mref();
    In this case, in fact, usual OOP stuff for hereditariness does not kick in, because perl already has a method to call.

    I agree with moritz about avoiding syntaxes that go beyond readability. On the other hand, I think that the following remains inside the realm of readability:

    $self->get_mref(...)->($self);
    although I'd probably go for a temporary variable anyway, just to stress the fact that you're getting a method to call on $self.

    perl -ple'$_=reverse' <<<ti.xittelop@oivalf

    Io ho capito... ma tu che hai detto?
        But does that matter when all the arguments are there (other than OO based things, like inheritance & polymorphism, not working obviously)?
Re: method dispatch question
by dragonchild (Archbishop) on Jul 09, 2008 at 13:52 UTC
    No-one else has bitten, so I will. WHY?? What on earth is your real-world application that needs to do this?

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
      What on earth is your real-world application that needs to do this?

      If you refer to the problem of method dispatch per se, the application is not so unusual: We have several "variations" of a method, which can be selected by a key, which gets calculated on run-time. One obvious implementation for this is to have a hash, which maps the keys to the methods. Just a normal dispatch table, only that it is on "class methods" instead of "normal" subs.

      Now since Perl does not "really" distinguish between methods and non-methods (it is more like a conceptual idea of the programmer, respectively how to use them), I can of course do it like I would with a function dispatch table, which means that I can put $self explicitly as a first parameter to the dispatched functions, as I have shown in my OP.

      But when I encounter a problem like this, I am usually interested in finding other solutions. In this case, I was interested whether a solution would exist which would still allow me to use the syntax $self->... for calling the method, only that to the right of -> is now not the name of the function, but a variable holding the reference to the function. How this is done, was nicely explained by parv.

      Having seen how easy this is, I became interested whether one could also omit the auxiliary variable holding the method reference. This turned out not to be so easy.

      So, finding ways to put "everything into one single expression", is not so much a need, but curiosity, paired with my experience that by investigating this type of problems, we often learn a lot about the language in question - or at least I do. In the past, more than once a question like this, has brought me insight into new ways to solve things easier...

      -- 
      Ronald Fischer <ynnor@mm.st>
        So, you have this idea of multiple actions that can be taken, but on an object instead of just as regular dispatch. So, something like an event loop?

        My criteria for good software:
        1. Does it work?
        2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (3)
As of 2024-04-25 16:25 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found