in reply to Re^3: Short form (ternary) if else
in thread Short form (ternary) if else

Ken, I really do understand the scope thing. I just screwed it up when I first posted. But given the correct scope...

Are you saying that the below code should work?
my $vxdg; (exists $vxdgs{$node}{$disk}) ? $vxdg=$vxdgs{$node}{$disk} : $vxdg="";
or will it only work like:
my $vxdg = exists $vxdgs{$node}{$disk} ? vxdgs{$node}{$disk} : '';

Replies are listed 'Best First'.
Re^5: Short form (ternary) if else
by kcott (Archbishop) on Feb 08, 2012 at 23:06 UTC

    Both will work (i.e. run without error) but the first form won't do what you're expecting due to operator precedence. The second form is preferable anyway because it is shorter, less complicated and easier to read. Take a look at the perlop manpage - under Conditional Operator for an explanation.

    I suggest you write some test code for yourself rather than just asking whether this or that code will or won't work. You can do this sort of thing on the commandline:

    ken@ganymede: ~/tmp $ perl -Mstrict -Mwarnings -E 'my $x = 1 ? 1 : 0; say $x;' 1 ken@ganymede: ~/tmp $ perl -Mstrict -Mwarnings -E 'my $x; 1 ? $x=1 : $x=0; say $x;' 0 ken@ganymede: ~/tmp $ perl -Mstrict -Mwarnings -E 'my $x; 1 ? ($x=1) : ($x=0); say $x;' 1 ken@ganymede: ~/tmp $

    -- Ken

      I'm surprised by this result:
      ken@ganymede: ~/tmp $ perl -Mstrict -Mwarnings -E 'my $x; 1 ? $x=1 : $x=0; say $x;' 0
      Do you know why $x becomes 0?
        operator precedence; ? : binds tighter than =. So

        1 ? $x=1 : $x=0

        really means

        (1 ? $x=1 : $x)=0

        which is then the same as

        ($x=1)=0

        which is why $x becomes 0.
        You can use assignments within ? :, you just need to parenthesize them

        1 ? $x=1 : ($x=0)

        Adding parentheses to the second statement to show precedence, we get:

        ( 1 ? ( $x=1 ) : $x ) = 0;

        As the 2nd and 3rd arguments are lvalues, you can assign to the ternary operator. As the first argument (1) is TRUE, the assignment becomes:

        ( $x=1 ) = 0;

        Which effectively boils down to:

        $ perl -Mstrict -Mwarnings -E 'my $x; ($x = 1) = 0; say $x;' 0

        The link I gave above (perlop manpage - under Conditional Operator) has a fuller description.

        -- Ken

Re^5: Short form (ternary) if else
by AnomalousMonk (Archbishop) on Feb 09, 2012 at 03:07 UTC

    If you want to see how Perl sees and parses your code (and in particular, via the  -p "extra parens, please" switch, how it interprets precedence), use the O and Deparse modules:

    >perl -wMstrict -MO=Deparse,-p -le "my ($node, $disk, %vxdgs) = (0, 0); my $vxdg; (exists $vxdgs{$node}{$disk}) ? $vxdg = $vxdgs{$node}{$disk} : $vxdg = ''; " BEGIN { $^W = 1; } BEGIN { $/ = "\n"; $\ = "\n"; } use strict 'refs'; (my($node, $disk, %vxdgs) = (0, 0)); my($vxdg); ((exists($vxdgs{$node}{$disk}) ? ($vxdg = $vxdgs{$node}{$disk}) : $vxd +g) = ''); -e syntax OK
Re^5: Short form (ternary) if else
by Marshall (Canon) on Feb 09, 2012 at 00:06 UTC
    Ken's comments are "spot on".
    The second form is far preferable because it is just far more clear!

    There is however another "layer" of complexity to this question that you are probably not aware of....

    When testing for the existence of some value in a 2D hash, Perl will "autovivify" the first dimension(s) if it(they) doesn't exist already. The code below demonstrates this behavior. This can lead to some side-effects and strange results later.

    This statement:

    $var = $vxdg{$node}{$disk} //= '';
    creates the entire multi-dimensional key and assigns it the value of '' if it wasn't already defined. This '//=' operator is specific to Perl. It is like ||= except that it tests for "defined-ness" instead of "truth-ness". Whether or not this is a "good thing" or "not" depends upon the application.

    I'm just suggesting that you should be aware of what happens when testing for existence or "defined-ness" of multi-dimensional hash array values.

    #!/usr/bin/perl -w use strict; use Data::Dumper; my %vxdg; my $var; my ($node,$disk) = (3, "C:"); print "node= $node disk=$disk\n"; print "orignal hash is:", Dumper \%vxdg; print "\$var is: \"", (defined $var) ? $var : "undefined", "\"","\n"; $var = exists $vxdg{$node}{$disk} ? $vxdg{$node}{$disk} : ''; print "the hash is now...after checking for",'$vxdg{$node}{$disk}:', "\n", Dumper \%vxdg; print "\$var is: \"", (defined $var) ? $var : "undefined", "\"","\n"; print "\n***Starting over..***\n"; %vxdg=(); $var=undef; print "orignal hash is:", Dumper \%vxdg; $var = $vxdg{$node}{$disk} //= ''; print "the hash is now...:", "\n", Dumper \%vxdg; print "\$var is: \"", (defined $var) ? $var : "undefined", "\"","\n"; __END__ node= 3 disk=C: orignal hash is:$VAR1 = {}; $var is: "undefined" the hash is now...after checking for$vxdg{$node}{$disk}: $VAR1 = { '3' => {} }; $var is: "" ***Starting over..*** orignal hash is:$VAR1 = {}; the hash is now...: $VAR1 = { '3' => { 'C:' => '' } }; $var is: ""