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

test.pl:
#!/usr/bin/perl sub foo :lvalue { if( $_[0] ) { $bar } else { $baz } } foo($ARGV[0]) = 32; print "Bar: $bar, Baz: $baz\n"
buu@its01:~$ perl test.pl 1 Bar: 32, Baz:
buu@its01:~$ perl test.pl 0 Can't return a temporary from lvalue subroutine at test.pl line 15.
Anyone know whats happening here?

(Same thing happens with 5.6.1 and 5.8.5)

Replies are listed 'Best First'.
Re: Oddness with lvalue and if/else blocks
by Zaxo (Archbishop) on Sep 09, 2004 at 01:52 UTC

    Not what you asked, but the trinary op is an lvalue, making this construction easy and correct:

    sub foo :lvalue { $_[0] ? $bar : $baz }
    I think the problem with yours is that the last evaluated statement in the sub is the whole if..else block.

    After Compline,
    Zaxo

      Note that there is subtlety involved. According to -MO=Deparse,-x7 the compiler does turn his if/else construct into something pretty close to

      $_[0] ? do { $bar } : do { $baz }

      where the do-blocks are B::Deparse's way of explaining the world more so than they really exist.

      That's obviously not ultimately the same as an explicit ternary, though.

      Makeshifts last the longest.

Re: Oddness with lvalue and if/else blocks
by Aristotle (Chancellor) on Sep 08, 2004 at 23:43 UTC

    If you add a warn or some other statement, it happens in both cases. I'm currently trying to see if anything in the B::Concise output is an indication.

    Update: this is the result, reduced to its relevant bits:

    $ perl -MO=Concise,-tree t.pl # from your code verbatim: # ... |-scope-+-ex-nextstate | `-ex-rv2sv---<4>gvsv(*bar) `-<9>leave-+-<6>enter |-<7>nextstate(main 2 t.pl:11) `-ex-rv2sv---<8>gvsv(*baz) # after adding warns # ... |-<i>leave-+-<c>enter | |-<5>nextstate(main 1 t.pl:7) | |-<7>warn[t1]---<6>pushmark | |-<8>nextstate(main 1 t.pl:8) | `-ex-rv2sv---<9>gvsv(*bar) `-<i>leave-+-<c>enter |-<d>nextstate(main 2 t.pl:12) |-<f>warn[t2]---<e>pushmark |-<g>nextstate(main 2 t.pl:13) `-ex-rv2sv---<h>gvsv(*baz)

    As you see, the truth-branch of your condition works in the cases where the compiler doesn't set up a complete scope for it for whatever reason.

    Don't ask me exactly why that is a problem and what this all means, yet. :-)

    Makeshifts last the longest.

      This is easier to look at when you write /leavesublv/gvsv( "bar' ) vs /leavesublv/leave/gvsv( 'baz' ). It appears to be a bug where the return of $bar isn't generating a leave. Both conditions should trigger the warning as long as leave doesn't notice that its next op is going to be a leavesublv. So two bugs - one is that you didn't get the warning enough and one that leave isn't aware of leavesublv.

      It also looks like the fix for this makes the common case ever so slightly slower.