in reply to Re: postfix syntax enlightenment
in thread postfix syntax enlightenment

The perlsyn doc on statment modifiers says that a line such as my $var = 1 if $test; leads to an undefined behaviour: you don't know what happens to the variable if the condition evaluates to false.

Are you sure of that? This is not what I understand from the document you quote. My understanding, from reading aforesaid document, is that my $var if $test; is undefined. But this is quite different. Please note that this is not a troll at all, I would really like to know. Although, in such a case, I would normally declare the variable and assign it in separate instructions, I think there might be some of my programs (at most very few) where I used something equivalent to my $var = 1 if $test; and I don't recall having encountered any problem with this type of syntax (but it is also quite possible that I actually never did it, I would in principle be suspicious with such a construct with conditional declaration).

This seems to work according to my expectations:

$ perl -e 'my $c = 1 if 1; print $c;' 1 ~ $ perl -e 'my $c = 1 if 0; print $c;'

Replies are listed 'Best First'.
Re^3: postfix syntax enlightenment
by kcott (Archbishop) on Mar 28, 2014 at 21:02 UTC

    The documentation that Eily references says this:

    NOTE: The behaviour of a my, state, or our modified with a statement modifier conditional or loop construct (for example, my $x if ...) is undefined. The value of the my variable may be undef, any previously assigned value, or possibly anything else. Don't rely on it. Future versions of perl might do something different from the version of perl you try it out on. Here be dragons.

    The example it gives is:

    my $x if ...

    The example you give is:

    my $var if $test;

    I see nothing that invalidates Eily's example of:

    my $var = 1 if $test;

    Another important point from that is: "Future versions of perl might do something different from the version of perl you try it out on."

    I don't think showing us the results of just two tests is particularly meaningful.

    [While it's probably a moot point, your second one-liner (with my $c = 1 if 0) doesn't indicate whether $c's value is a zero-length string or undef.]

    -- Ken

      Hi Ken,

      Thank you for your answer and I have usually the highest regard for your posts (and I upvoted your answer even though I still disagree with it, because I think it is well explained). To set the record straight, I am not trying to invalidate Eily's example, far from that, I am just trying to understand what exactly is undefined behavior here. And I am still not convinced at all that:

      my $var if $test;
      and
      my $var = 1 if $test;
      are equivalent in terms of the behavior being defined or not. These are two quite different types of statements. Assuming just one second, only for the sake of argument, they had both a defined behavior, I would still consider the first one as almost entirely useless (and deserving to be undefined), and the second one as making some sense (although lacking clarity, to say the least). Therefore, if the author of the documentation meant to say that my $var = 1 if $test; also has undefined behavior, then I would submit that this should probably be added to the documentation, because having someone using this second type of construct is much more likely than than the first one.

      Again, I am not saying that Eily is wrong, I just don't know and I truly would like to know. While I usually would probably not use something like:

      my $var = 1 if $test;
      I would really not swear that I have never used something like:
      my $value = $1 if $foo =~ /^\w+(\d+)/; do_something($value) if defined $value;
      And, as far as I can say, I would expect this to work fine.

      Concerning the one-liners, I agree that they were very short examples I added at the last minute to my post, this is an improved version of them:

      $ perl -Mstrict -Mwarnings -e ' my $c = 1 if 1; print $c;' 1 ~ $ perl -Mstrict -Mwarnings -e ' my $c if 1; print $c;' Use of uninitialized value $c in print at -e line 1.
      I am not saying that observed behavior is describing the Perl standard, but since there is no real Perl 5 standard, in a certain way, only the compiler can tell us what to think when the documentation is ambiguous. And I think the documentation is definitely ambiguous in that specific case. Having said that, I perfectly understand the warning: "Future versions of perl might do something different..." Just not sure that it applies to something like:
      my $var = 1 if $test;

        It may be that you're reading more into the given example than is intended in the documentation. Examples tend to be short and to the point: complex examples can often obscure the main idea that the example is intending to convey. "my $x if ..." would be one of the shortest examples that showed a lexical declaration with a statement modifier.

        "... my, state, or our ..." are all keywords that introduce a lexical declaration. There's nothing in the documentation that says anything about how those keywords might be used: it mentions no restrictions or exemptions. Just because the example only shows "my $x", I see nothing that suggests more complex examples would behave any differently (with respect to producing in an undefined result which should not be relied upon). All of these would be equally valid examples but tend to (increasingly) hide the point being made (and might even suggest exclusion of simpler examples):

        my ($x) if ... my $x = 1 if ... my ($x, $y) = (1, 2) if ... my ($x, $y, $z) = (split /\s+/ => $spaced_tokens)[3 .. 5] if ...

        Similarly, "... modified with a statement modifier conditional or loop construct ..." mentions no restrictions or exemptions. The example uses "if"; however, there's nothing to suggest that any of the other modifiers (unless, while, until, for, foreach or when) would behave any differently (with respect to producing in an undefined result which should not be relied upon).

        For what it's worth, I played around with the OP code a bit when it was first posted. In one test, I added a check for whether $test1 was defined after "my $test1 = ... if ...;". In the first call to test(), $test1 was undefined; in the second call it was defined:

        $test1 is not defined. Use of uninitialized value $test1 in concatenation (.) or string at ./ +pm_example.pl line 13. test1 after hash assignment: '' i = 0 test1 after defaulting to i: '0' $test1 is defined. test1 after hash assignment: '0' i = 1 test1 after defaulting to i: '0'

        That looks like exactly the unpredictable results described in: "The value of the my variable may be undef, any previously assigned value, or possibly anything else. Don't rely on it."

        -- Ken

        my with postfix if is the singular problem, regardless of any assignment, present or absent.
Re^3: postfix syntax enlightenment
by AnomalousMonk (Archbishop) on Mar 28, 2014 at 20:22 UTC
    My understanding, from reading aforesaid document, is that my $var if $test; is undefined.

    But the cited doc in Re: postfix syntax enlightenment sez "NOTE: The behaviour of ... is undefined.", clearly, I think, referring to behavior (or behaviour, if you will) rather than to the state of the lexical being undef (if I correctly understand your understanding). (The link is to 5.18.2 docs, but my local 5.10.1 docs say essentially the same, but without reference to state or our.)