http://qs321.pair.com?node_id=11138374

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

Hi

I was expecting that a prototype sub foo(&) will parse foo {$x} with precedence foo(sub {$x}) but ...

use strict; use warnings; sub foo (&){ } sub bar {} my ($Q,$t) = (10,2); bar ($Q) + bar ($t); foo {$Q} + foo {$t}; # line 12

C:/Strawberry/perl/bin\perl.exe -w d:/tmp/pm/sym.pl Too many arguments for main::foo at d:/tmp/pm/sym.pl line 12, near "}; +" Execution of d:/tmp/pm/sym.pl aborted due to compilation errors.

what is happening here?

Is that a bug or a feature?

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

update: s/d/foo/

update

that's unfortunate, prototypes don't seem to influence precedence at all ... :/

use strict; use warnings; sub bla($) {shift} my ($Q,$t,$res) = (10,2); sub tst { print $res= bla $Q / bla $t; } use B::Deparse; print B::Deparse->new('-p')->coderef2text(\&tst);

C:/Strawberry/perl/bin\perl.exe -w d:/tmp/pm/sym.pl { use warnings; use strict; print(($res = bla(($Q / bla($t))))); }

Replies are listed 'Best First'.
Re: (SOLVED) parsing problems with prototype blocks (updated)
by haukex (Archbishop) on Nov 03, 2021 at 13:57 UTC

    Unfortunately I think you're right, these are just a few additional thoughts.

    that's unfortunate, prototypes don't seem to influence precedence at all

    Nitpick: They do influence precedence/parsing, just not in the way you want - from Prototypes:

    sub mygrep (&@) mygrep { /foo/ } $a, $b, $c sub myrand (;$) myrand 42
    ... treated specially by the parser. mygrep() is parsed as a true list operator, myrand() is parsed as a true unary operator with unary precedence the same as rand() ...
    $ perl -MO=Deparse,-p -e 'sub myrand (;$) {} rand 123 / rand 456; myra +nd 123 / myrand 456' sub myrand (;$) {} rand((123 / rand(456))); myrand((123 / myrand(456))); $ perl -MO=Deparse,-p -e 'sub mygrep (&@) {} grep {$A} + grep {$B} 1; +mygrep {$A} + mygrep {$B} 1' sub mygrep (&@) {} grep( {$A;} grep( {$B;} 1)); mygrep(sub {$A;}, mygrep(sub {$B;}, 1));

    ... so builtins do basically behave the same way in terms of precedence - though as of 5.34 there isn't a builtin with a prototype of (&) or even (&@); grep has no prototype, which indicates it is treated specially by the parser (which is why I had to add the 1 after the above grep lest it be a syntax error instead of Not enough arguments).

    Update: Relevant: Named Unary Operators

      On a similar note, I was once experimenting with constants (i.e. sub(){value} with empty prototype) returning objects with overloaded operators.

      I got bitten by the fact that < was interpreted as the start of of a diamond operator, leading to a compilation error.

      (I showed this here, but can't find the thread ATM)

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

Re: (SOLVED) parsing problems with prototype blocks (precedence)
by ikegami (Patriarch) on Nov 03, 2021 at 16:09 UTC

    «+ foo {$t}» is found where an argument would be. An expression is expected, so «+» is treated as a unary operator, so

    foo {$Q} + foo {$t}

    is the same as

    foo {$Q} foo {$t}

    To get the desired result, you can use the following:

    ( foo {$Q} ) + foo {$t}

    Update: Replaced "Fixed:" with clearer wording.

      UPDATE: I may have misunderstood your post, and FIXED is meant as workaround.

      > Fixed: ( foo {$Q} ) + foo {$t}

      no, it's not, because this was what I expected.

      > + is treated as the unary operator, so

      And it would be binary

      use strict; use warnings; sub foo (&){ shift->()} sub baz (&){ shift->()} sub bar {3} my ($Q,$t,$res) = (10,3); sub tst { ( foo {$Q} ) + baz {$t}; } use B::Deparse; print B::Deparse->new('-p')->coderef2text(\&tst); print tst();
      C:/Strawberry/perl/bin\perl.exe -w d:/tmp/pm/sym.pl { use warnings; use strict; (foo(sub { $Q; } ) + baz(sub { $t; } )); }13

      update
      FWIW I chose + for an example which at least compiles b/c of the ambiguity.

      I originally used / which fails without having any unary meaning (it's seen as the start of a m//)

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

        Yes, by "Fixed: ( foo {$Q} ) + foo {$t}", I meant "You can fix the problem by using ( foo {$Q} ) + foo {$t}"