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

$ perl -e 'tied( sub {}->() )' Can't modify non-lvalue subroutine call at -e line 1.
My question is: Who's trying to modify anything?

If I were reading this, my reaction would be “You tie variables, not values, so it doesn't make sense to test the result of a subroutine call using tied” (I tried it in a fit of optimism anyway); but my question is not so much why this approach doesn't work as why I get an error about an attempted modification when none exists. Is tied doing something bizarre internally like trying to assign to its argument and seeing if a STORE method fires?

(On a presumably much simpler note, I don't see why

$ perl -e 'tied sub {}->()' Can't modify reference constructor in tied at -e line 1, near "})"
parses differently. According to perlop, -> is higher in priority than anything but terms and list operators. As near as I can tell from perlfunc, tied isn't a list operator. I don't know if it's a ‘term’ because I'm not really sure what a ‘term’ is. :-)

UPDATE: As tye pointed out in the Chatterbox, perl -e 'tied sub {}->()' doesn't actually produce that error. It was all a dream!)

Replies are listed 'Best First'.
Re: tied, or modified?
by tswall (Monk) on Oct 22, 2009 at 20:01 UTC
    Isn't sub a higher priority than ->? (My noobness and I have no business commenting on such business, so I hope I don't offend anyone).

    To quote perlop:

    "Also parsed as terms are the do {} and eval {} constructs, as well as subroutine and method calls, and the anonymous constructors [] and {}."

    And left terms and list operators have a higher precedence than ->.

    I won't tackle your first question, as it is WAY out of my league.

      Isn't sub a higher priority than ->? (My noobness and I have no business commenting on such business, so I hope I don't offend anyone).

      Welcome to Perlmonks, and feel free to dive right into the discussions without apology. Especially since you took the time to quote from the documentation in support of your answer, no offence was taken (or given).

      I was surprised, not by sub {}->() parsing as (sub {})->() (though I had to try it to make sure that it was the case), but rather by tied sub {}->() parsing as ( tied sub {} )->().

        It doesn't look like that is how it gets parsed (in 5.10.0):
        # perl -MO=Deparse,-p -e 'tied( sub {}->() )' tied({sub { } }->()); -e syntax OK
        In other words,
        tied( { sub {} }->() );
        which I think is equivalent to the following, because the braces there are denoting a block rather than a hash:
        <c> tied( ( sub {} )->() );
Re: tied, or modified?
by ikegami (Patriarch) on Nov 10, 2009 at 18:23 UTC
    The parsing is probably handled by some generic routine that was told tied's arg must be an lvalue. You didn't provide an lvalue. The generic routine tries to explain what an lvalue is (something modifiable) and that one wasn't provided ("Can't modify X"), but the message does not fit this particular case.
Re: tied, or modified?
by ikegami (Patriarch) on Nov 13, 2009 at 23:34 UTC

    perl -e 'tied sub {}->()'
    doesn't parse differently than
    perl -e 'tied( sub {}->() )'
    and neither produce the "Can't modify reference constructor" error.

    I think you tried
    perl -e 'tied { sub {}->() }'

    perl -e 'tied { sub {} }->()'

    which is what Deparse gives for the above two programs. This is a bug in Deparse. It's not representative of the opcode tree produced by the first two programs.

      Hmm, Perl 5.8.9 gives me

      $ perl -MO=Deparse -e 'tied sub {}->()' tied {sub { } }->(); -e syntax OK
      which gives a different error:
      $ perl -e 'tied { sub {} }->()' Not a subroutine reference at -e line 1.

      The code you mention doesn't compile:

      $ perl -e 'tied { sub {}->() }' Can't modify anonymous hash ({}) in tied at -e line 1, at EOF Execution of -e aborted due to compilation errors.

      Thanks for taking the time to think about this. I've cut and pasted these straight from the command line to avoid further incidents. :-)

        which gives a different error:

        As it should. Like I said, it's a bug in Deparse.

        An anonymous hash is the anonhash opcode.

        $ perl -MO=Concise,-exec -e'{}' 1 <0> enter 2 <;> nextstate(main 1 -e:1) v:{ 3 <0> pushmark s 4 <@> anonhash vK* 5 <@> leave[1 ref] vKP/REFC -e syntax OK

        Note the lack of anonhash in the code that's actually produced by tied sub {}->().

        $ perl -MO=Concise,-exec -e'tied sub {}->()' 1 <0> enter 2 <;> nextstate(main 2 -e:1) v:{ 3 <0> pushmark s 4 <0> pushmark sRM 5 <$> anoncode[CV ] lRM 6 <1> refgen sK/1 7 <1> rv2cv sK/NO() 8 <1> entersub[t2] sKRMS/NO(),TARG,1 9 <1> tied vK/1 a <@> leave[1 ref] vKP/REFC -e syntax OK

        Deparse is wrong to add an anon hash constructor. Therefore, trying to execute the output of Deparse makes no sense.