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>
Re: method dispatch question
by parv (Parson) on Jul 09, 2008 at 11:53 UTC
|
| [reply] [d/l] |
|
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>
| [reply] [d/l] [select] |
|
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 ${...}.
| [reply] [d/l] [select] |
|
|
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);
| [reply] [d/l] [select] |
|
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.
| [reply] [d/l] |
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)
| [reply] [d/l] |
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?
| [reply] [d/l] [select] |
|
the following notations are perfectly equivalent:
Other than one being a method call and the other not. Which is exposed by Devel::Caller::called_as_method.
| [reply] |
|
But does that matter when all the arguments are there (other than OO based things, like inheritance & polymorphism, not working obviously)?
| [reply] |
|
|
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:
- Does it work?
- Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
| [reply] |
|
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>
| [reply] |
|
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:
- Does it work?
- Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
| [reply] |
|
|
|