Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Question re $obj->$action(@args) syntax

by blazar (Canon)
on Mar 21, 2007 at 12:31 UTC ( #605829=perlquestion: print w/ replies, xml ) Need Help??
blazar has asked for the wisdom of the Perl Monks concerning the following question:

First of all, let me premise that this is a "just out of curiosity kinda question".

As of the Subject, if $obj holds a blessed reference, and $action is a subref, then in

$obj->$action(@args);

the latter will be called as if it were an object method. (Similarly if instead of $obj you have a bareword, in which case it will be called like a class method.) I like to use this mechanism, sometimes, to implement callbacks. "Of course", it also works if instead of $obj you have an expression returning an object. OTOH generally wherever a variable holding a subref is used, an expression returning one (especially an anonymous sub altogether) could be used instead, but I don't think in this one: any kind of parentheses I may put around the expression would be parsed as some kind of dereferencing. Similarly, I can't hope in putting anything in ${ } beacause that is parsed as scalar dereferencing as of itself.

As I said above, not that I really need this "feature", but is there a way to "inline" a subref as hinted above? Somehow it strikes me as as something that should be doable if not for anything else for completeness sake...

Now, just like you can disambiguate between grouping parens and sub call's ones with a unary plus, what I want if not available in other ways, may have a syntax like the following:

$obj->+(EXPR)(@args);

Admittedly, I suppose that could make a hell to parse...

Comment on Question re $obj->$action(@args) syntax
Select or Download Code
Re: Question re $obj->$action(@args) syntax
by kyle (Abbot) on Mar 21, 2007 at 13:26 UTC

    I don't think I understand your question. I tried this:

    use strict; use warnings; use Data::Dumper; my $obj = bless {}, 'Foo'; my $action = sub { print Dumper( \@_ ) }; $obj->$action( 'hello' ); __END__ $VAR1 = [ bless( {}, 'Foo' ), 'hello' ];

    ...and that works. Are you saying you want to do something like "$obj->sub { do_stuff(); etc(); }( @args );" so that you don't need an explicit $action? It seems that you're basically doing something like:

    { @_ = ( $obj, @args ); # rest of 'sub' goes here }

    "Inline" code doesn't need to be made into a sub. Am I misunderstanding your question?

      I don't think I understand your question. I tried this:
      # snip code
      ...and that works.

      Of course!

      Are you saying you want to do something like "$obj->sub { do_stuff(); etc(); }( @args );" so that you don't need an explicit $action?

      Exactly, out of orthogonality considerations.

      It seems that you're basically doing something like:
      { @_ = ( $obj, @args ); # rest of 'sub' goes here }
      "Inline" code doesn't need to be made into a sub. Am I misunderstanding your question?

      Possibly so: I certainly don't understand your reply. Are you saying that you would expect the following to work as (I) intended?

      use strict; use warnings; use Data::Dumper; my $obj = bless {}, 'Foo'; $obj->{ print Dumper( \@_ ) }( 'hello' ); __END__

      If so, then it doesn't because ->{ is interpreted as hash dereferencing:

      $VAR1 = []; Use of uninitialized value in subroutine entry at 605841.pl line 7. Can't use string ("") as a subroutine ref while "strict refs" in use a +t 605841.p l line 7.

      OTOH Anno and grinder completely addressed my question.

        Are you saying that you would expect the following to work as (I) intended?

        No, not at all. What I'm saying is that the code I wrote achieves the goal of removing the extra variable (i.e., there's no explicit $action code ref) while not achieving the goal of a "$obj->blah(@args)" style syntax. To be longer and more explicit:

        use strict; use warnings; use Data::Dumper; my $obj = bless {}, 'Foo'; my @args = ( 'hello' ); { @_ = ( $obj, @args ); print Dumper( \@_ ) } __END__ $VAR1 = [ bless( {}, 'Foo' ), 'hello' ];

        The functional difference between this and what you're shooting for is (in addition to the gross syntax difference) that this one is taking copies in @_ instead of aliases.

        So, perhaps a better short version of what I'm saying is, "if all you want to do is eliminate a variable, do this..." Sorry for the confusion.

Re: Question re $obj->$action(@args) syntax
by Anno (Deacon) on Mar 21, 2007 at 13:31 UTC
    That's documented in perlop, description of the Arrow Operator. For the right side to hold a method, it must be a bare method name or a simple variable. No expressions allowed.

    Anno

Re: Question re $obj->$action(@args) syntax
by grinder (Bishop) on Mar 21, 2007 at 14:13 UTC
    As I said above, not that I really need this "feature", but is there a way to "inline" a subref as hinted above? Somehow it strikes me as as something that should be doable if not for anything else for completeness sake...

    This topic comes up from time to time on p5p. The short answer is that while theoretically it makes sense from some sort of orthogonal point of view, the parser code is not particularly amenable in this respect. From memory it's got something to do with disambiguating curlies (is this a hash deref or a code block coming up).

    That said, you can inline a subref lookup, if you are brave and insist on this approach. Given the package:

    package Foo; sub new { bless { val => $_[1] }, $_[0]; } sub zug { my $self = shift; my $arg = shift; return "$arg $self->{val} $arg"; } sub zwang { my $self = shift; my $arg = shift; return join( ' ', ($self->{val}) x $arg ); }

    Then the tradtional as-per-perlop approach would be:

    my $f = Foo->new('doot'); my @meth = (qw(zug zwang)); # doesn't work: # print $f->$meth[rand @meth](3); my $m = $meth[rand @meth]; print $f->$m(3), $/;

    But you can avoid creating the intermediate lexical by dereferencing a scalar reference:

    my $f = Foo->new('doot'); # update: with subrefs: my @meth = (\&Foo::zug, \&Foo::zwang); print $f->${\$meth[rand @meth]}(3);

    But you have to admit that the traditional approach is a little easier for people to comprehend.

    updated: added an initialistion to show that the code works with true coderefs as well as bareword method names.

    • another intruder with the mooring in the heart of the Perl

      This topic comes up from time to time on p5p. The short answer is that while theoretically it makes sense from some sort of orthogonal point of view, the parser code is not particularly amenable in this respect. From memory it's got something to do with disambiguating curlies (is this a hash deref or a code block coming up).

      That is exactly what I had in mind: orthogonality and consistency. (Well, Perl 5 already deviates from them whenever convenient, and in very useful ways, so I'm not going mad about them either, but... well... you know...) And that's what I expected too: parsing difficulties.

      That said, you can inline a subref lookup, if you are brave and insist on this approach.

      Thank you for the suggestion. It is exactly the kind of trick I insistently thought that ought to exist:

      #!/usr/bin/perl use strict; use warnings; use Data::Dumper; (bless {}, 'Foo')->${\sub { print Dumper \@_ }}(1,2,3); __END__

      Which is strange, because I made some tests and I was quite sure to have tried something along these lines too. Probably there were some spurious error that made me infer the wrong conclusion.

      But you have to admit that the traditional approach is a little easier for people to comprehend.

      Oh, for that... seconded all the way!

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (3)
As of 2014-07-13 05:36 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    When choosing user names for websites, I prefer to use:








    Results (247 votes), past polls