http://www.perlmonks.org?node_id=952567

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

I don't think I understand the ternary ? : in perl. Can you help me understand why the below code is not working as expected?
(exists $vxdgs{$node}{$disk}) ? my $vxdg=$vxdgs{$node}{$disk} : my $vxdg="";
I am looking for a short form for...
if (exists $vxdgs{$node}{$disk}) { my $vxdg=$vxdgs{$node}{$disk}; } else { my $vxdg=""; }
Thank you.

Replies are listed 'Best First'.
Re: Short form (ternary) if else
by Riales (Hermit) on Feb 08, 2012 at 19:59 UTC
    I think what you're looking for is this:
    my $vxdg = exists $vxdg{$node}{$disk} ? $vxdg{$node}{$disk} : '';
    Also, in your if/else statement, if you declare $vxdg inside the if/else like you are doing, it goes out of scope by the time you get out of the if/else block.
      Yes, that works beautifully! Thank you! I realize the scope issue as well. So, what I understand is that ternary form is only for use after an assignment (=) operator? Is that correct?

        No, it doesn't have to be used in conjunction with assignment. Consider:

        printf("X is %s\n", defined $X ? $X : 'undefined');

        Or:

        sub get_name { # ... return wantarray ? ($firstname, $middlename, $lastname) : "$firstname $lastname"; }

        Yes and no... It is typically at it's most useful after an assignment, and it's use is that it generates a value, but that doesn't necessarily mean it needs to be used in an assignment. Others have given examples, but the essential thing to remember is that the ternary operator returns a value. if does not: It is a flow-control operator.

        So, where it does need to be used is where Perl would expect a value. Assignments are one common case of that.

Re: Short form (ternary) if else
by SuicideJunkie (Vicar) on Feb 08, 2012 at 19:57 UTC

    Perhaps you want to declare $vxdg outside the if, and only assign the value inside the if?

    my $vxdg = (exists $foo) ? $bar : 'baz';

Re: Short form (ternary) if else
by kcott (Archbishop) on Feb 08, 2012 at 20:25 UTC

    The ternary operator exists in many programming languages and is often a stumbling block for many who encounter it for the first time. I'm sure I scratched my head over it too. Here's an example of usage:

    use strict; use warnings; my %hash = ( abc => 123 ); my $abc = exists $hash{abc} ? $hash{abc} : 0; my $xyz = exists $hash{xyz} ? $hash{xyz} : 0; print "ABC = $abc : XYZ = $xyz\n";

    This outputs:

    ABC = 123 : XYZ = 0

    Another thing you need to know is that variables declared with my are lexical. With your example code, this means the first $vxdgs only exists in the if block and the second $vxdgs only exists in the else block; furthermore, they are two completely separate variables with their own values.

    From your question, I believe the code you want is:

    my $vxdg = exists $vxdgs{$node}{$disk} ? $vxdgs{$node}{$disk} : "";

    -- Ken

      The ternary operator exists in many programming languages and is often a stumbling block for many who encounter it for the first time

      I must be decidedly odd - stop nodding at the back eyepopslikeamosquito - as I distinctly remember coming across the ternary operator in Perl and understanding it immediately. But at the same time thinking that I cannot see a use for it. Then, very soon afterwards I found a place where I could, and did use it...

      For a while I overused it in many places where if...else would have been more appropriate. I think I have the right balance between these options now.

      Thanks all! I realize the scope issue. So, what I understand is that ternary form is only for use after an assignment (=) operator? Is that correct?

        That's not correct. The ternary operator will generate some sort of value - what you do with that value is up to you. You could, for example, use it to create a boolean return value:

        return defined $result ? 1 : 0;

        You can also nest ternary operators. Say you wanted to compare two numbers and produce: 1 if the first number was bigger; 0 if they were the same; -1 if the second number was bigger:

        my $cmp = $x > $y ? 1 : $x == $y ? 0 : -1;

        -- Ken

Re: Short form (ternary) if else
by InfiniteSilence (Curate) on Feb 08, 2012 at 19:58 UTC

    perl -e 'my $n = 10; (1)? $n++ : $n--; print qq~This is $n\n~;'
    Prints:
    This is 11

    Celebrate Intellectual Diversity

Re: Short form (ternary) if else
by Mandrake (Chaplain) on Feb 09, 2012 at 11:07 UTC
    Or probably
    my $vxdg = $vxdgs{$node}{$disk} || "";
    thanks
      my $vxdg = $vxdgs{$node}{$disk} || "";
      This is short and sweet, but doesn't take into account a hash value of 0, which could be a valid value. So, if I had a hash value of 0, perl would evaluate it as false, and set the variable to blank.

      Whenever I see this I usually see this right afterwards:

      if ( $vxdg != '' ) {

      Where they should probably be using:

      if ( $vxdg ) {

      Which would make the || "" in the assignment unnecessary.

      Yes, I understand sometimes zero and the empty string are distinct values from undef in many business rules, but I don't think that applies as aften as many coders believe.

Re: Short form (ternary) if else
by trwww (Priest) on Feb 09, 2012 at 04:09 UTC

    Why not just:

    my $vxdg = $vxdgs{$node}{$disk}

    ?

Re: Short form (ternary) if else
by JavaFan (Canon) on Feb 08, 2012 at 22:38 UTC
    I am looking for a short form for...
    if (exists $vxdgs{$node}{$disk}) { my $vxdg=$vxdgs{$node}{$disk}; } else { my $vxdg=""; }
    Well, assuming %{$vxdgs}{$node} isn't a tied hash with side-effects, and $vxdgs{$node}{$disk} isn't a tied scalar with side-effects, your code is a noop. Both blocks assign something to a scalar variable, with both scalars going out of scope directly after the assignment.