2009/9/11 Steve Bertrand <st...@ibctech.ca>:
> Uri Guttman wrote:
>> it is actually very simple to understand. the key point to knowing it
>> and how to use it is that the 2 value expressions SHOULD NOT have side
>> effects. that means changing something by assignment or other
>> modification. your example below is one exception to that.
>
> Since I use functions/methods to perform side effects frequently, I
> believe what you mean is that in *most* cases, the conditional op
> shouldn't ever have anything that must be evaluated in one of the
> either/or fields.
>
> For example, this:
>
> my $num    = 1;
> my $add_to = 2;
>
> my $ret = ( $foo == 1 ) ? ( $num + $add_to ) : 2;
>
> ...SHOULD _always_ ( where possible ) be written as:
>
> my $expr_result = ( $num + $add_to );
>
> my $ret = ( $foo == 1 ) ? $expr_result : 2;

No, that's not it. ($num + $add_to) is an expression with no
side-effects. The only purpose of the expression is to calculate a
value, which can then be assigned to a variable (or passed to a
function, or used to index an array, or whatever). In this case, you
can't actually tell whether or not ($num + $add_to) was evaluated if
the false branch was taken, because even if it were it has no
side-effects and you've discarded its value.

(shift) is an expression with side-effects. The expression returns a
value, the first element of @_, *and also* removes that element from
the front of @_. This modification of @_ is known as a side-effect,
because it changes the state of something rather than just calculating
a value for the expression. After evaluating the expression (shift) to
find its value, @_ has changed. If you throw away the result of shift,
it still has an effect on the state of the program. [Nitpick: shift
returns the first element of @_ within a subroutine, but outside it
uses @ARGV instead]

Uri's point about side-effects is one of style. Generally ?: is used
for calculating a value to be used in an expression, most often in the
form:

$target = <condition> ? <trueval> : <falseval>;

The expressions <trueval> and <falseval> are primarily used to
calculate a value. Other examples of using the ?: to calculate a value
are:

myfunc( $cond ? $foo : $bar);
$target += $cond ? $foo : $bar; # or -= or *= or any other
modify-assignment operator

You *could* use the ?: operator differently, as a control-flow statement:

$push_to_left
   ? push @left, $value
   : push @right, $value;

but this is really, really bad style. Note how we are no longer using
the ?: operator to choose between different values, but instead to
choose between different side-effects: either @left changes, or @right
does. When you are choosing between functionality and not values, you
should use a proper "if" or "unless":

if ($push_to_left) {
   push @left, $value;
}
else {
   push @right, $value;
}

You could, in theory, do this:

push @{ $push_to_left ? \...@left : \...@right }, $value;

but the mucking about with references to make it work makes it less
readable than the if() version, IMO.

In your original example:
my $args = ( ref $_[0] eq 'HASH' ) ? shift : {} ;

the ?: operator chooses between two values, but one of the expressions
has a side-effect (of changing @_). The side-effect is actually good,
and should be kept in the conditional. If we took it out:

my $val = shift;
my $args = ( ref $val eq 'HASH' ) ? $val : {} ;

then we've changed the meaning, since the shift will always happen
now, and if $val is not a hashref its value still gets removed from
@_, probably not what you want. This is why your original example is
an exception to the "avoid side-effects" rule.

I actually think the style rule regarding ?: is slightly different to
what Uri said:

** Don't use ?: for control-flow. Only use it to select between two values. **

If one of the values is gotten using a side-effect, that can be ok.
But if the side-effect of the trueval or falseval is the only purpose
of the ?: statement, you should rewrite it, either in the form
'$target = condition ? foo : bar;' or as an if statement.

Philip

--
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/


Reply via email to