Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

postfix syntax enlightenment

by RobertCraven (Sexton)
on Mar 28, 2014 at 18:15 UTC ( [id://1080128]=perlquestion: print w/replies, xml ) Need Help??

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

Hi All,
I am wondering why $test1 the code below stays 0.
sub test{ my $i = shift; my $params = shift; my $test1 = $params->{test} if exists $params->{test}; print "test1 after hash assignment:\t\t$test1\n"; $test1 = $i if ! defined $test1; print "i = $i\ttest1 after defaulting to i:\t$test1\n"; } for my $i(0..3){ &test($i,{}); }

Output: Use of uninitialized value $test1 in concatenation (.) or string at te +st.pl line 19. test1 after hash assignment: i = 0 test1 after defaulting to i: 0 test1 after hash assignment: 0 i = 1 test1 after defaulting to i: 0 test1 after hash assignment: 0 i = 2 test1 after defaulting to i: 0 test1 after hash assignment: 0 i = 3 test1 after defaulting to i: 0 <br>

I figured out that the line my $test1 = $params->{test} if exists $params->{test}; causes the trouble, but I am wondering why.
Thanks!

Replies are listed 'Best First'.
Re: postfix syntax enlightenment
by Eily (Monsignor) on Mar 28, 2014 at 18:35 UTC

    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.

    Anyway in your case, even if you had written my $var; $var = $params->{test} if exists $params->{test}, you would still have the same result, because unless $params->{test} exists, you don't put any value in $test1.

    A simple way to do what you want is to write:

    my $i = shift; my $params = shift; my $test1 = $i; # $test1 is $i by default $test1 = $params->{test} if exists $params->{test}; # change its value + when appropriate

    You may be interested by the defined or operator (which would still lead to autovivification of the $params->{test} value in your case), and the ternary operator to solve problems similar to this one.

      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;'

        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

        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.)

      One thing is still not entirely clear to me: what if my is within the condition of a postfix if?
      use strict; if (my $x = 1) { print "x = $x\n" } # $x is not available outside of the if scope # this works, but is it valid? 1 if my $y = 3; print "y = $y\n"; for my $i (my @n = 1..3) { print "i = $i, n = (@n)\n" } # @n is not available here # the following code works as expected, but, again, is it valid? @ARGV = qw(/ /usr//local /etc/ sbin/); tr#/##s && s#(?<!^)/$## for my @copies = @ARGV; print "$_\n" for @copies;
        ... what if my is within the condition of a postfix if? ... is it valid?

        This is the way I look at it: The thing to remember is that the modifier clause (if that's the proper terminology) of a modified statement modifies the behavior of the statement. In order to do so, the modifier clause must always be evaluated. The ambiguity in a statement like
            my $x if $some_conditional;
        concerns whether (and when) the lexical definition is evaluated, but  $some_conditional (or whatever expression may be there) must always be evaluated.

        In a statement like
            0 if my $x = 1;
        there is no ambiguity: the lexical is always defined (and, in this example, initialized). Similarly, in the statement
            do_something($_) for my @ra = @rb;
        the for-loop initialization expression  my @ra = @rb must always be evaluated (including the definition and initialization of its lexical) in order that for may be able to control (i.e., modify the behavior of) the statement.

        So, is
            0 if my $x;
        and its ilk valid? Unquestionably (and unambiguously and without deprecation) yes, I would say. (But I'm too lazy right now to dig up a documentation citation.)

        Consider the following code. Also consider running | compiling it with  -MO=Deparse,-p added (often enlightening in these cases).

        c:\@Work\Perl\monks>perl -wMstrict -le "no warnings 'syntax'; ;; 0 if my $x = 42; print qq{$x}; ;; my @orig = qw(foo bar baz); tr{a-z}{A-Z} && printf qq{'$_' } for my @copy = @orig; print ''; print qq{(@orig) (@copy)}; ;; for (0 .. 2) { die 'Oops...' if my $x; print qq{\$x (still) undefined here} if not defined $x; $x = 42; print qq{\$x is $x here}; } " 42 'FOO' 'BAR' 'BAZ' (foo bar baz) (FOO BAR BAZ) $x (still) undefined here $x is 42 here $x (still) undefined here $x is 42 here $x (still) undefined here $x is 42 here

        (Also consider running your code with warnings enabled. And strict.)

Re: postfix syntax enlightenment
by Anonymous Monk on Mar 28, 2014 at 19:49 UTC
Re: postfix syntax enlightenment
by swinging_simian (Initiate) on Mar 31, 2014 at 08:38 UTC
    Hi

    Thanks to all for comments. An enlightening discussion. Hopefully next time I might be able to reply a little earlier, but for some reason I wasn't permitted (maybe as I'm a newbie on here).


    Nath

    (aka, author of the *other* post)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1080128]
Approved by kcott
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others sharing their wisdom with the Monastery: (4)
As of 2024-04-20 06:10 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found