Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

my (0?$a:$b): a koan

by educated_foo (Vicar)
on May 04, 2011 at 16:52 UTC ( [id://902937]=perlmeditation: print w/replies, xml ) Need Help??

What does this print? And why? Bonus points if you can get either question right without running it.
$a=1; $b=2; sub { my (0?$a:$b) = 3; print "a=$a\nb=$b\n" }->()
It took me awhile to figure it out, but it was enlightening about the workings of "my":

Replies are listed 'Best First'.
Re: my (0?$a:$b): a koan
by wind (Priest) on May 04, 2011 at 19:11 UTC

    My guess was either (1,3) or ('', 3), leaning toward the former

    I'd probably write the example code like the following to keep it a little simpler and to focus on the actual mechanism that is occuring

    my $x = 1; my $y = 2; { my (0?$x:$y) = 3; print "x=$x\ny=$y\n" }

    Very interesting result though, thank you for the explanation

    Btw, do you have an explanation for why B::Deparse gets it wrong? I've hardly ever used that module so not even sure exactly what it's trying to do.

      Your version is indeed simpler. I had put the sub call in there to see if I could use a parameter for the ternary test (Perl gets angry about your trying to lexicalize @_ if you do that), but failed to remove it.

      do you have an explanation for why B::Deparse gets it wrong?
      B::Deparse walks through the op-tree reconstructing a Perl program, and I'm guessing that its author didn't anticipate whatever weird optree you get from a ternary inside a "my". That, or it gets defeated by constant folding, just like here:
      $ perl -MO=Deparse -e 'print 0?$a:$b' print $b;
        > or it gets defeated by constant folding

        thats the point, compare the optree of my (0?$a:$b)="X" with my ($b)="X".

        Deparse has no chance to see any difference

        lanx:~$ perl -MO=Concise -e 'my (0?$a:$b)="X";print $a' c <@> leave[1 ref] vKP/REFC ->(end) 1 <0> enter ->2 2 <;> nextstate(main 1 -e:1) v:{ ->3 7 <2> aassign[t3] vKS ->8 - <1> ex-list lK ->5 3 <0> pushmark s ->4 4 <$> const[PV "X"] s ->5 - <1> ex-list lK ->7 5 <0> pushmark s ->6 6 <0> padsv[$b:1,2] lPRM*/LVINTRO ->7 8 <;> nextstate(main 2 -e:1) v:{ ->9 b <@> print vK ->c 9 <0> pushmark s ->a a <0> padsv[$a:1,2] l ->b -e syntax OK
        lanx:~$ perl -MO=Concise -e 'my ($b)="X";print $a' c <@> leave[1 ref] vKP/REFC ->(end) 1 <0> enter ->2 2 <;> nextstate(main 1 -e:1) v:{ ->3 7 <2> aassign[t2] vKS ->8 - <1> ex-list lK ->5 3 <0> pushmark s ->4 4 <$> const[PV "X"] s ->5 - <1> ex-list lK ->7 5 <0> pushmark s ->6 6 <0> padsv[$b:1,2] lPRM*/LVINTRO ->7 8 <;> nextstate(main 2 -e:1) v:{ ->9 b <@> print vK ->c 9 <0> pushmark s ->a - <1> ex-rv2sv sK/1 ->b a <#> gvsv[*a] s ->b -e syntax OK

        Note line a: In the first example $a is coded as entry "$a" from a lexical pad and in the second it's the scalar value of glob *a from a symbol table.

        IMHO you found a case where the compiler should better warn about undefined behavior.

        Cheers Rolf

        UPDATE: we had a discussion about this just few weeks ago, but I can't find it. Take this instead: 'my' with 'if 0' retains old value

        UPDATE: And here the warning I'm missing:

        perl -wce 'my $a if 0; print $a' Deprecated use of my() in false conditional at -e line 1. -e syntax OK

        UPDATE: Found it! see A curious case of of my() and Re^4: A curious case of of my() (What is GLOBAL?)

        I'm guessing that its author didn't anticipate whatever weird optree you get from a ternary inside a "my".

        There is no "weird optree". By the time Deparse gets its hands on the optree, the ternary has been optimised away.

        What's left is exactly the same as if the ternary (and $a) had never existed in the source.

        If there is a bug, then it is that the optimisation doesn't undo the local declaration of $a.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: my (0?$a:$b): a koan
by ikegami (Patriarch) on May 05, 2011 at 06:25 UTC

    The following behaviour is observed (i.e. this isn't a guess):

    • It compiles and runs. (I consider this a bug.) That's not the case for my argument list expressions that don't constant-fold into a list of simple variables.
    • In the sub, $a and $b are declared as lexicals since the values of the package variables aren't used.

    my has compile-time actions and run-time actions.

    • The compile-time action declares the lexicals.
    • The run-time action ensures the lexicals are cleared or replaced on scope exit.

    From the observed behaviour, I deduce the following compile-time behaviour:

    • When encountering a variable fetch, if parsing the argument list of my, treat it as a variable decleration instead.
    • After parsing a my, check if its argument list is a plain variable list. If not, throw an error.
    • Constant folding of my's argument list happens before the above check.

    That makes

    my (0?$a:$b) = 3;

    equivalent to

    (0 ? (my $a) : my $b ) = 3;

    and

    my $a if 0; my ($b) = 3;

    (minus the warning).

Re: my (0?$a:$b): a koan
by BrowserUk (Patriarch) on May 04, 2011 at 16:58 UTC

    Guess:

    a=1 b=3

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      That was mine, too, but it's wrong ;-). It actually prints...
      a= b=3
      ... and why it does is less-than-obvious.
Re: my (0?$a:$b): a koan
by JavaFan (Canon) on May 05, 2011 at 09:47 UTC
    I think my(EXPR?$x:$y) = 3; is equivalent to:
    my $x = 3 if EXPR; my $y = 3 if !EXPR;
    which is a known issue, and may do unexpected things if EXPR is false (although there has been code out there that (mis)uses this). Since 5.10 there has been a warning on
    my $x if EXPR;
    is EXPR can be determined to be false at compile time (constant folded to 0).

    I wouldn't worry about my(0?$x:$y) too much. It's not something people will be do by accident - it isn't documented to work, so people who do it shouldn't be surprised if their code no longer works after upgrading Perl.

      I wouldn't worry about my(0?$x:$y) too much.
      Oh, I'm not "worried" -- there's no need to either deprecate or document it. I just think: (1) it is surprising that it parses at all, since I thought "my" took a list of variables; and (2) it shows the compile- and run-time effects of "my" in an interesting way.

        it is surprising that it parses at all, since I thought "my" took a list of variables

        I suspect that it takes any expression, then checks if the expression is valid.

        >perl -e"my ( f($x, $y.) );" syntax error at -e line 1, near ".) " Execution of -e aborted due to compilation errors.

        The catch here is that that constant folding happens before the check.

        Another allowed expression:

        >perl -e"my(my(my(my $sharona)))" >

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://902937]
Approved by LanX
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (8)
As of 2024-04-18 10:15 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found