experchange > perl

Rainer Weikusat (11-01-18, 07:22 PM)
Line of code I wrote today (in a foreach loop):

$in_binary = $_->{'x-in-binary'} || next;

This works as intended: If the hash key has a non-empty value (string
value guaranteed), it's going to be assigned to $in_binary. Otherwise,
the next is evaluated which terminates the current iteration.

This could also be written as

$in_binary = $_->{'x-in-binary'} or next;

This assigns the value associated with the hash key to $in_binary,
evaluating the next if the assigned value was empty which has the same
effect but in a different way.

Does somebody see a reson why one or the other should be preferred?
Don Piven (11-02-18, 02:31 AM)
On 11/1/18 12:22, Rainer Weikusat wrote:
[..]
> evaluating the next if the assigned value was empty which has the same
> effect but in a different way.
> Does somebody see a reson why one or the other should be preferred?


"and", "or", "xor", and "not" have the lowest precedence of any Perl
operator, so if you use them primarily for flow control, they'll pretty
much do what it looks like they should do.

Using C-style operators (&&, ||, et al) for flow control, or using "or",
"and", et al in expressions -- especially in assignments -- can bite you
in interesting ways due to the assignment operators having lower
precedence than the C-style operators but higher precedence than "and",
"or", et al.

Compare "$a += $b || $c" with "$a += $b or $c".
Certes (11-02-18, 04:02 AM)
On 01/11/2018 17:22, Rainer Weikusat wrote:
[..]
> evaluating the next if the assigned value was empty which has the same
> effect but in a different way.
> Does somebody see a reson why one or the other should be preferred?


It depends what value you want $in_binary to have if
$_->{'x-in-binary'} is false (e.g. "") or that key isn't in the hash.

The first version will assign whatever value next returns to $in_binary.
I can't find that value documented anywhere but it happens to be undef
in the implementation of perl 5.22 I'm using.

The second version always sets $in_binary to $_->{'x-in-binary'}.

If you don't care then I would go for the second version as it is much
clearer and doesn't set a variable to an implementation-dependent value.
Ben Bacarisse (11-02-18, 04:35 AM)
Certes <none> writes:

> On 01/11/2018 17:22, Rainer Weikusat wrote:


I don't think they are the same. See my example below.

>> Does somebody see a reson why one or the other should be preferred?

> It depends what value you want $in_binary to have if
> $_->{'x-in-binary'} is false (e.g. "") or that key isn't in the hash.
> The first version will assign whatever value next returns to $in_binary.
> I can't find that value documented anywhere but it happens to be undef
> in the implementation of perl 5.22 I'm using.


Can you post an example?

The code /looks/ like it assigns the value of 'next', but in my tests it
seems the implied jump happens before any assignment can occur. For example

$v = 42;
for (0) {
print "use $_: ";
$v = $_ || next;
}
print "$v\n";

prints "use 0: 42".

I'm not saying this is what Perl says must happen, just what I observe
with Perl v5.26.2. I would equally not have been surprised to see
something (maybe undef) being assigned to $v before the 'next' kicks in.
In that sense, using || is unclear -- I am not sure what the language
specification says should happen.

> The second version always sets $in_binary to $_->{'x-in-binary'}.


Yup. If you replace || with or in the above you get "using 0: 0". The
assignment always happens. This behaviour is clear, and can easily be
deduced from the documentation.

> If you don't care then I would go for the second version as it is much
> clearer and doesn't set a variable to an implementation-dependent
> value.


I agree that using or is much clearer, provided the semantics are as you
want. If you *wants* the "assign or skip" behaviour that I see, I am
not sure you can rely on it (especially since you report different
results).
Certes (11-02-18, 11:43 AM)
On 02/11/2018 02:35, Ben Bacarisse wrote:
> The code /looks/ like it assigns the value of 'next', but in my tests it
> seems the implied jump happens before any assignment can occur. For example
> $v = 42;
> for (0) {
> print "use $_: ";
> $v = $_ || next;
> }
> print "$v\n";
> prints "use 0: 42".


You're right. I had run essentially the same test without initialising
$v. I had assumed that "$v = $_ || something;" would inevitably assign
some value to $v. But "next" works immediately rather than at the end
of the statement, which is why it has no documented value: that value
could never be used anywhere.
Rainer Weikusat (11-02-18, 04:44 PM)
Ben Bacarisse <ben.usenet> writes:
[..]
> prints "use 0: 42".
> I'm not saying this is what Perl says must happen, just what I observe
> with Perl v5.26.2.


That's what must happen because of the precedence of ||,

[rw@doppelsaurus]~#perl -MO=Deparse,-p -e '$a = $b || next'
($a = ($b || next));

vs

[rw@doppelsaurus]~#perl -MO=Deparse,-p -e '$a = $b or next'
(($a = $b) or next);

'next' is nothing special in Perl, it's just an op(erator) whose only
effect is to cause a side effect (control transfer). As it gets
evaluated before the assignment, no assignment takes place.

I originally wrote this with || and later remembered the higher
precedence. The original statement worked but in a different way than I
had thought it would work.
Rainer Weikusat (11-02-18, 04:49 PM)
Certes <none> writes:
> On 01/11/2018 17:22, Rainer Weikusat wrote:
> It depends what value you want $in_binary to have if
> $_->{'x-in-binary'} is false (e.g. "") or that key isn't in the hash.


Doesn't matter. That's part of a loop which is supposed to perform an
operation on all objects in the list its looping over which have a
filename guaranteed to be different from '' (empty string) or '0'.
Ben Bacarisse (11-02-18, 11:25 PM)
Rainer Weikusat <rweikusat> writes:

> Ben Bacarisse <ben.usenet> writes:
> That's what must happen because of the precedence of ||,


I know the precedence. My doubt was caused by not knowing Perl's rules
for when side effects take place.

> 'next' is nothing special in Perl, it's just an op(erator) whose only
> effect is to cause a side effect (control transfer). As it gets
> evaluated before the assignment, no assignment takes place.


Does the language guarantee that all side effects are complete before
any more of the containing expression is evaluated? It would make
prefect sense if this were guaranteed because the only reason I know of
to leave it unspecified is to allow for compiler optimisations, but
that's not a priority for Perl.
Rainer Weikusat (11-03-18, 12:16 AM)
Ben Bacarisse <ben.usenet> writes:
> Rainer Weikusat <rweikusat> writes:


[$x = $y->{bla} || next]

> Does the language guarantee that all side effects are complete before
> any more of the containing expression is evaluated?


That's the wrong question ;-). Perl is de-facto defined by the behaviour
of perl. That compiles expressions in order of precedence into op-trees
(aka 'threaded code') which are then evaluated. 'next' is just another
'op function' which is called during evaluation of the corresponding
tree node. Hence, the side effect[*] takes place at this time.
[*] This should really be called 'effect' as its the intended purpose
and not something which "also happens" ...
Similar Threads