syntax query: ($var++ && next) if /match/

J

Justin C

I have:

#!/usr/bin/perl

use strict;
use warnings;

my $seen = 0;
my @arr = qw/john paul george ringo/;

for (@arr) {
($seen = 1 && next) if /^paul/;
next unless $seen;
print $_, "\n";
}

__END__

which prints no output. But if I change the `&&` to a comma it does as
expected.... ($seen = 1, next) if ...

I've just read perldoc perlop for Comma Operator, and for &&, but I
don't understand why one works and the other doesn't. Can anyone explain
this in simple terms?

Justin.
 
R

Rainer Weikusat

Justin C said:
I have:

#!/usr/bin/perl

use strict;
use warnings;

my $seen = 0;
my @arr = qw/john paul george ringo/;

for (@arr) {
($seen = 1 && next) if /^paul/;
next unless $seen;
print $_, "\n";
}

__END__

which prints no output. But if I change the `&&` to a comma it does as
expected.... ($seen = 1, next) if ...

I've just read perldoc perlop for Comma Operator, and for &&, but I
don't understand why one works and the other doesn't.

The precedence of && is higher than that of =, meaning,

$seen = 1 && next is equivalent to $seen = (1 && next) or (as
B::Deparse would tell you) $seen = next. And next doesn't return a
value, hence, $seen is never set. The obvious way to fix this:

--------------
#!/usr/bin/perl

use strict;
use warnings;

my $seen = 0;
my @arr = qw/john paul george ringo/;

for (@arr) {
(($seen = 1) && next) if /^paul/;
next unless $seen;
print $_, "\n";
}
--------------

leads to a particularly useless warning:

[rw@sapphire]/tmp $perl a.pl
Found = in conditional, should be == at a.pl line 10.
george
ringo

It certainly shouldn't be == but I assume that exploiting the
short-circuiting-ness of && and || for control flow control has
meanwhile also been declared as 'simply not kosher !!1' by the
'rotting Perl'[*] thought police ..

A half-way German word play: 'modern' is 'modern' in German and adding
appending a d to that yields modernd <=> rotting.
 
W

Willem

Rainer Weikusat wrote:
) The precedence of && is higher than that of =, meaning,
)
) $seen = 1 && next is equivalent to $seen = (1 && next) or (as
) B::Deparse would tell you) $seen = next. And next doesn't return a
) value, hence, $seen is never set. The obvious way to fix this:

...
) for (@arr) {
) (($seen = 1) && next) if /^paul/;

Or you use 'and':

for (@arr) {
($seen = 1 and next) if /^paul/;

) next unless $seen;
) print $_, "\n";
) }


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
R

Rainer Weikusat

Willem said:
Rainer Weikusat wrote:
) The precedence of && is higher than that of =, meaning,
)
) $seen = 1 && next is equivalent to $seen = (1 && next) or (as
) B::Deparse would tell you) $seen = next. And next doesn't return a
) value, hence, $seen is never set. The obvious way to fix this:

...
) for (@arr) {
) (($seen = 1) && next) if /^paul/;

Or you use 'and':

for (@arr) {
($seen = 1 and next) if /^paul/;

Arguably a better idea. But the parenthesises can be dropped as well,
making this

$seen = 1 and next if /^paul/;

which I consider to be preferable.
 
K

Keith Thompson

Rainer Weikusat said:
Arguably a better idea. But the parenthesises can be dropped as well,
making this

$seen = 1 and next if /^paul/;

which I consider to be preferable.

Some might consider

if (/^paul/) {
$seen = 1;
next;
}

to be preferable. You can put it on one line:

if (/^paul/) { $seen = 1; next; }

if you're afraid of wearning out your enter key.
 
C

C.DeRykus

Justin C said:
I have:

use strict;
use warnings;
my $seen = 0;
my @arr = qw/john paul george ringo/;
for (@arr) {
   ($seen = 1 && next) if /^paul/;
   next unless $seen;
   print $_, "\n";
}

which prints no output. But if I change the `&&` to a comma it does as
expected.... ($seen = 1, next) if ...
I've just read perldoc perlop for Comma Operator, and for &&, but I
don't understand why one works and the other doesn't.

The precedence of && is higher than that of =, meaning,

$seen = 1 && next is equivalent to $seen = (1 && next) or (as
B::Deparse would tell you) $seen = next. And next doesn't return a
value, hence, $seen is never set. The obvious way to fix this:

--------------
#!/usr/bin/perl

use strict;
use warnings;

my $seen = 0;
my @arr = qw/john paul george ringo/;

for (@arr) {
        (($seen = 1) &&  next) if /^paul/;
        next unless $seen;
        print $_, "\n";}

--------------

leads to a particularly useless warning:

[rw@sapphire]/tmp $perl a.pl
Found = in conditional, should be == at a.pl line 10.
george
ringo

It certainly shouldn't be == but I assume that exploiting the
short-circuiting-ness of && and || for control flow control has
meanwhile also been declared as 'simply not kosher !!1' by the
'rotting Perl'[*] thought police ..

As you noted, $seen never gets any assignment in
the case of $seen = next. So I think Perl is just
letting you know something is amiss and its best
guess ("rotten" or not) is that you may have meant
$seen == 1 since there's no assignment.

I think a clearer, more direct warning though would
have been something like:

variable $seen is not assigned a value
in expression $seen = next.

No lame guess needed.
A half-way German word play: 'modern' is 'modern' in German and adding
appending a d to that yields modernd <=> rotting.

The Gedankenpolizei's warning needs a little
modernizing...
 
J

Jürgen Exner

Rainer Weikusat said:
The precedence of && is higher than that of =, meaning,

$seen = 1 && next is equivalent to $seen = (1 && next) or (as
B::Deparse would tell you) $seen = next. And next doesn't return a
value, hence, $seen is never set. The obvious way to fix this:
(($seen = 1) && next) if /^paul/;

Actually no. The perlish way to do it is to use '&&' for expressions and
'and' for flow control. Then most of the time the precedences will
automatically fall into place.

jue
 
R

Rainer Weikusat

Keith Thompson said:
[...]
[...]
Arguably a better idea. But the parenthesises can be dropped as well,
making this

$seen = 1 and next if /^paul/;

which I consider to be preferable.

Some might consider

if (/^paul/) {
$seen = 1;
next;
}

to be preferable.

Or

/^paul/ and $seen = 1, next;

You can put in on several lines if you're afraid your enter key might
feel lonely otherwise

/^paul/
and
$seen
=
1
,
next
;

[SCNR]

Seriously, though, a block in Perl is a separate lexical scope and
this means that executing a conditional block is more expensive than
using a 'non-block' equivalent. When using perl -MO=Conicse,-exec
in order to the a list of 'ops' performed by the Perl code, the

$seen = 1 and next if /^paul/

results in

l </> match(/"^paul"/) s/RTIME
m <|> and(other->n) vK/1
n <$> const[IV 1] s
o <0> padsv[$seen:1,5] sRM*
p <2> sassign sKS/2
q <|> and(other->r) vK/1
r <0> next v*

while the if (...) { } compiles to

l </> match(/"^paul"/) s/RTIME
m <|> and(other->n) vK/1
n <0> enter v
o <;> nextstate(main 3 a.pl:9) v
p <$> const[IV 1] s
q <0> padsv[$seen:1,7] sRM*
r <2> sassign vKS/2
s <;> nextstate(main 3 a.pl:10) v:{
t <0> next v*
u <@> leave vKP
 
R

Rainer Weikusat

C.DeRykus said:
[...]

The obvious way to fix this:
--------------
#!/usr/bin/perl

use strict;
use warnings;

my $seen = 0;
my @arr = qw/john paul george ringo/;

for (@arr) {
        (($seen = 1) &&  next) if /^paul/;
        next unless $seen;
        print $_, "\n";}

--------------

leads to a particularly useless warning:

[rw@sapphire]/tmp $perl a.pl
Found = in conditional, should be == at a.pl line 10.
george
ringo
[...]

As you noted, $seen never gets any assignment in
the case of $seen = next. So I think Perl is just
letting you know something is amiss and its best
guess ("rotten" or not) is that you may have meant
$seen == 1 since there's no assignment.

The broken code compiles without warnings while both working variants
[$seen = 1 and next, ($seen = 1) && next] generate it.
 
C

C.DeRykus

C.DeRykus said:
[...]









The obvious way to fix this:
--------------
#!/usr/bin/perl
use strict;
use warnings;
my $seen = 0;
my @arr = qw/john paul george ringo/;
for (@arr) {
        (($seen = 1) &&  next) if /^paul/;
        next unless $seen;
        print $_, "\n";}
--------------
leads to a particularly useless warning:
[rw@sapphire]/tmp $perl a.pl
Found = in conditional, should be == at a.pl line 10.
george
ringo
[...]

As you noted, $seen never gets  any assignment in
the case of $seen = next. So I think Perl is just
letting you know something is amiss and its best
guess  ("rotten" or not) is that you  may have meant
$seen == 1 since there's no assignment.

The broken code compiles without warnings while both working variants
[$seen = 1 and next, ($seen = 1) && next] generate it.


You're right...

In summary these two - which don't twist the mind
in strange, unholy ways - do generate the warning:

perl -we"$seen=$_=0;{($seen=1) && next if /^paul/}"
perl -we"$seen=$_=0;{ $seen=1 and next if /^paul/}"

But, these bizarre (or semi-bizarre )ones don't:

perl -we"$seen=$_=0;{ 1 && next if /^paul/}"
perl -we"$seen=$_=0;{ 1 and next if /^paul/}"
perl -we"$seen=$_=0;{ $seen and next if /^paul/}"
perl -we"$seen=$_=0;{ $seen && next if /^paul/}"
perl -we"$seen=$_=0;{ $seen==1 and next if /^paul/}"
perl -we"$seen=$_=0;{ $seen==1 && next if /^paul/}"

Ideally, I think it'd be nice if Perl would at
least warn that something like {$seen = next}
doesn't assign to $seen at all.
 
J

Justin C

Keith Thompson said:
Rainer Weikusat said:
Rainer Weikusat wrote:
[...]
) (($seen = 1) && next) if /^paul/;
[...]
($seen = 1 and next) if /^paul/;

Arguably a better idea. But the parenthesises can be dropped as well,
making this

$seen = 1 and next if /^paul/;

which I consider to be preferable.

Some might consider

if (/^paul/) {
$seen = 1;
next;
}

to be preferable.

Or

/^paul/ and $seen = 1, next;

You can put in on several lines if you're afraid your enter key might
feel lonely otherwise

/^paul/
and
$seen
=
1
,
next
;

C'mon guys, now you're getting silly. I was going for a balance between
brevity and legibility. Using a block does not have much brevity, but
has a lot of legibility - it was what my original code had (I was
younger and less experienced then). OTOH $seen = 1 and next if... is
brief to the detriment of legibility (or understandability), at least
for me. So far I have decided that ($seen = 1 and next) if ... is the
best solution for me... let's see what else this thread shows up before
I commit myself!

Justin.
 
J

Justin C

If your intention is to perform two operations,
relying on the quirk that your first operation
evaluates to "true" is quite dirty.

I understand what you mean by 'relying on the quirk that [my] first
operation evaluates to true...' (I've been accused of that before, but
I'm open to education as to why I shouldn't be doing these things, and I
try to not repeat bad practice). But I'm not sure I am doing as you
suggest, if I am would you please explain it differently as I'm not
seeing it as explained. I am not trying to assign the result of 'next'
to $seen (as someone posted was happening in one of the versions of the
line, in another post).

My intention is to set a variable $seen to 1 (true) (for use later), to
stop processing the current item and move on to the next if $_ matches
certain criteria.

The code from which the above is a reduction, is used to read input from
a file with man lines and a certain format. Until a line matching a
particular string is reached all is discarded. Once a particular line is
reached then a switch is thrown ($seen = 1) and the following lines are
processed by my program. Once a further line is reached I call 'last' as
I don't wish to even look at the rest of the file.

(I'm deliberately ignoring the operator binding issue,
and addressing intent, here).

If $seen were $absent, with inverted logic, you'd need
to change the operator from && to || which is just horrible.

Perl has perfectly good syntax for "bundling" operations;
abusing (or attempting to abuse) a conditional operator
is not a good idea.

Yeah, I'm definitely lost now. I don't mean to be a PITA, but I don't
yet speak perl well enough - I understand some of the terminology, but
not enough to understand you here.


Justin.
 
J

Justin C

Rainer Weikusat wrote:
) The precedence of && is higher than that of =, meaning,
)
) $seen = 1 && next is equivalent to $seen = (1 && next) or (as
) B::Deparse would tell you) $seen = next. And next doesn't return a
) value, hence, $seen is never set. The obvious way to fix this:

...
) for (@arr) {
) (($seen = 1) && next) if /^paul/;

Or you use 'and':

for (@arr) {
($seen = 1 and next) if /^paul/;

[snip]

Ah, I see from perlop:

"...when used for control flow, Perl provides 'and' and 'or' operators.
The short-circuit behavious is identical."

Thanks, Willem. It appears that when I read there are somethings that
just don't get past the retina.

Justin.
 
R

Rainer Weikusat

Justin C said:
Keith Thompson said:
Rainer Weikusat wrote:
[...]

) (($seen = 1) && next) if /^paul/;
[...]

($seen = 1 and next) if /^paul/;

Arguably a better idea. But the parenthesises can be dropped as well,
making this

$seen = 1 and next if /^paul/;

which I consider to be preferable.

Some might consider

if (/^paul/) {
$seen = 1;
next;
}

to be preferable.

Or

/^paul/ and $seen = 1, next;

You can put in on several lines if you're afraid your enter key might
feel lonely otherwise

/^paul/
and
$seen
=
1
,
next
;

C'mon guys, now you're getting silly. I was going for a balance between
brevity and legibility. Using a block does not have much brevity, but
has a lot of legibility -

A text doesn't become easier to understand by adding more
non-alphanumeric characters to it.
it was what my original code had (I was
younger and less experienced then). OTOH $seen = 1 and next if... is
brief to the detriment of legibility (or understandability),

Why this, since it does exactly what its literal meaning appears to
be:

$seen = 1 and next if /^paul/

(set $seen to 1 and execute next if $_ matches /^paul/)
 
J

Jürgen Exner

Justin C said:
My intention is to set a variable $seen to 1 (true) (for use later), to
stop processing the current item and move on to the next if $_ matches
certain criteria.

What's wrong with an old-fashioned
if ($_ matches certain criteria) {
$seen = 1;
next;
}

Just because Perl has conditional statements doesn't mean that you have
to squeeze everything into that mold.

jue
 
R

Rainer Weikusat

Jürgen Exner said:
What's wrong with an old-fashioned
if ($_ matches certain criteria) {
$seen = 1;
next;
}

The signal-to-noise ratio of this encoding of this particular operation
is worse than that of the equivalent statement-modifier or logical
operating using variants. Additionally, it is less efficient although
this could be regarded as a deficiency of the perl compiler. The only
'positive' thing about it is that it looks more familiar to people who
are versed in 'other curly-bracket languages'.
 
S

sln

[...]
If your intention is to perform two operations,
relying on the quirk that your first operation
evaluates to "true" is quite dirty.

I understand what you mean by 'relying on the quirk that [my] first
operation evaluates to true...' (I've been accused of that before, but
I'm open to education as to why I shouldn't be doing these things, and I
try to not repeat bad practice). But I'm not sure I am doing as you
suggest,
[...]

Performing asignment as part of a conditional expression,
even variable modification, is not really a safe bet if you
want the remainder of the expression to be evaluated.

Furthermore, it lacks clarity and is hard to maintain,
even for the person who wrote it.

I think Perl tries to compensate its formal conditional
requirement of wrapping code in a block braces, spcifically
even 1 line, that for example C/C++ doesen't, with an offering
of code before conditional; ie: $seen=1 if (condition)

The more formal conditional structure of
if (condition){
code;
}
is preferred to me.
Yeah, I'm definitely lost now. I don't mean to be a PITA, but I don't
yet speak perl well enough - I understand some of the terminology, but
not enough to understand you here.

That could just as well have been said about C/C++.

-sln
 
S

sln

The signal-to-noise ratio of this encoding of this particular operation
is worse than that of the equivalent statement-modifier or logical
operating using variants. Additionally, it is less efficient although
this could be regarded as a deficiency of the perl compiler. The only
'positive' thing about it is that it looks more familiar to people who
are versed in 'other curly-bracket languages'.

I would disagree with this.

1. Efficiency is relative and insignificant
unless its your only line of code.

2. Like it or not, Perl is a curly-bracket language.
Try writing a program without them.
Since it is, the probability is that its hard to
maintain:
(code) if (condition);, or
code if condition;

3. The greatest benefit is reaped from clarity
of intent. If you want to focus on performance,
design it in with external lib calls, or
don't use Perl, use assembly or C.

Some constructs I like in RPN.
unless() is one of them when the code body
is not a conditional.

-sln
 
J

Jürgen Exner

Rainer Weikusat said:
The signal-to-noise ratio of this encoding of this particular operation
is worse than that of the equivalent statement-modifier or logical
operating using variants. Additionally, it is less efficient although
this could be regarded as a deficiency of the perl compiler. The only
'positive' thing about it is that it looks more familiar to people who
are versed in 'other curly-bracket languages'.

I disagree. This isn't one operation, it is two and they are quite
different. One assignment and one loop control jump. And therefore it
should look and feel like two operations, i.e. be separated into two
statements.
You can easily see how confusing it is to munge them together: in just
this very thread there are already at least three different
interpretions of what the OP intended the code to do.

It is just not worth this confusion. Consice code that is easy to
understand is way more important than shorting the code to the max.
Unless you are playing Perl golf, of course.

Also, I am not convinced about your efficieny argument. For one nobody
asked for the code to be as efficient as possible. And even if so I
would still find it hard to believe that an if statement is slower,
because in both cases the same operations are performed. Or actually in
case of the statement modifier there is even an additional and.
Not to mention that such micro-optimizations are rarely the right
approach. If a program is too slow then almost always a different
algorithm or a different overall approach is the answer. If you are
really depending upon such micro-optimizations then probably you should
have chosen a different programming language, probably one that allows
lower-level control like C or assembler.

jue
 
R

Rainer Weikusat

Justin C wrote:
[...]
which prints no output. But if I change the `&&` to a comma it does as
expected.... ($seen = 1, next) if ...

I've just read perldoc perlop for Comma Operator, and for&&, but I
don't understand why one works and the other doesn't. Can anyone explain
this in simple terms?

If your intention is to perform two operations,
relying on the quirk that your first operation
evaluates to "true" is quite dirty.

I understand what you mean by 'relying on the quirk that [my] first
operation evaluates to true...' (I've been accused of that before, but
I'm open to education as to why I shouldn't be doing these things, and I
try to not repeat bad practice). But I'm not sure I am doing as you
suggest,
[...]

Performing asignment as part of a conditional expression,
even variable modification, is not really a safe bet if you
want the remainder of the expression to be evaluated.

Provided the assigment returns the required value it is perfectly
safe.
Furthermore, it lacks clarity and is hard to maintain,
even for the person who wrote it.

Could you perhaps explain why you think that 'it lacks clarity and is
hard to maintain' (instead of just asserting that it does)?
I think Perl tries to compensate its formal conditional
requirement of wrapping code in a block braces, spcifically
even 1 line, that for example C/C++ doesen't, with an offering
of code before conditional; ie: $seen=1 if (condition)

This is probably supposed to prevent the so-called 'dangling else
problem' in C or C++ where some people apparently manage to fool
themselves into believing that identation could change semantics,
namely, that

if (a)
if (b) ...;
else ...;

would mean if (a) { if (b) ...; } else ... instead of
if (a) { if (b) ...; else ...; }. But as opposed to C or C++, blocks
are not 'free' at runtime in perl, although at least the 5.10.1
compiler can meanwhile optimize a single-statement conditional block
away and statement modifiers use to be documented as having the
advantage of 'being able to avoid the overhead of entering a block.

Independently of this, they make the text easier to read[*] for short,
conditionally executed sequences.

[*] This assumes that 'reading' happens left to right from top
to bottom of a text, *not* by indentation-based 'recursive
descent parsing'.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,077
Latest member
SangMoor21

Latest Threads

Top