While query

P

P.R.Brady

Why does 'while' fail to pop a blank string from an array in the following?

use strict;
use warnings;

my @array;
push @array,"";
push @array,"2";

while ($_= pop(@array)) {
print "popped $_ \n";
}

It returns the "2" but not the blank.

Regards
Phil
 
P

P.R.Brady

Scott said:
It doesn't fail to pop the blank string.

When the blank string is popped, $_= pop(@array) evaluates to false. The
while condition is no longer true, so control passes out of the while
loop without executing the code inside the loop.


Scott,
I clearly have a misunderstanding here. You are saying that the
$_=pop(@array) evaluates false because $_ is false?
Panic - where have I made this assumption elsewhere?

So to empty and process my array/stack I need to:
while (scalar(@array)) {
$_=pop(@array);
...
}

Thanks
Phil
 
A

A. Sinan Unur

Why does 'while' fail to pop a blank string from an array in the
following?

use strict;
use warnings;

my @array;
push @array,"";

This is an empty string. An empty string is evaluates to false in Perl.
push @array,"2";

while ($_= pop(@array)) {

The body of the while statement will not be executed if the condition is
false.
print "popped $_ \n";
}

It returns the "2" but not the blank.

Are you just trying to pop off array elements while the array is not
empty?

You could instead do

my @array = ('hello', '');

while(@array) {
my $x = pop @array;
print "Popped: [$x]\n";
}

__END__

C:\Scratch> perl t.pl
Popped: []
Popped: [hello]

Sinan
 
A

A. Sinan Unur

So to empty and process my array/stack I need to:
while (scalar(@array)) {
$_=pop(@array);
...
}

You could do

use strict;
use warnings;

my @array = ('hello', '');

while(@array and my ($x) = pop @array) {
print "Popped: [$x]\n";
}

__END__
 
P

Paul Lalli

Are you just trying to pop off array elements while the array is not
empty?

You could instead do

my @array = ('hello', '');

while(@array) {
my $x = pop @array;
print "Popped: [$x]\n";
}
__END__

Or the canonical way implemented by the magic while(<>){}:

while (defined ($_ = pop @array)){
print "Popped: $_\n";
}

pop returns undef if it is given a blank array as an argument.

Paul Lalli
 
P

Paul Lalli

I clearly have a misunderstanding here. You are saying that the
$_=pop(@array) evaluates false because $_ is false?
Panic - where have I made this assumption elsewhere?

In the general case, an assignment expression always returns the value
being assigned:
$x = ($y = foo()); #$x gets the value of foo()

In your specfic case, the while condition was testing the truthfulness
of the entire assignment expression.

Paul Lalli
 
P

Paul Lalli

I wrote in message news:gDg7d.166$ea6.130@trndny06...
my @array = ('hello', '');

while(@array) {
my $x = pop @array;
print "Popped: [$x]\n";
}
__END__

Or the canonical way implemented by the magic while(<>){}:

while (defined ($_ = pop @array)){
print "Popped: $_\n";
}

(I should have mentioned, of course, that this will fail to work if any
of the elements are undefined)

Paul Lalli
 
K

Keith Keller

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Why does 'while' fail to pop a blank string from an array in the following?

use strict;
use warnings;

my @array;
push @array,"";
push @array,"2";

while ($_= pop(@array)) {
print "popped $_ \n";
}

It returns the "2" but not the blank.

Others have already posted why; how about another how?

use strict;
use warnings;

my @array=('','2');

foreach (reverse @array)
{
print "''popped'' [$_]\n";
}


Probably less efficient than A. Sinan's suggestion, but I really like
using for/foreach to assign list/array values in turn to $_ (or to a
my'd scalar).

- --keith

- --
(e-mail address removed)-francisco.ca.us
(try just my userid to email me)
AOLSFAQ=http://wombat.san-francisco.ca.us/cgi-bin/fom

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (GNU/Linux)

iD8DBQFBXZh+hVcNCxZ5ID8RAgMyAJwMLFu0oqOGy8ri3njlWvz6iSdPKwCfQQ1e
JDulc8T/WZ92MCBFANn4l18=
=Iu0W
-----END PGP SIGNATURE-----
 
K

Keith Keller

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

use strict;
use warnings;

my @array=('','2');

foreach (reverse @array)
{
print "''popped'' [$_]\n";
}

Oops--this won't actually empty the array as the various pop-based
methods will. Depending on what the goal is, that may or may not be an
issue. (It does continue to loop if an element is undef, which also may
or may not be a concern.)

- --keith

- --
(e-mail address removed)-francisco.ca.us
(try just my userid to email me)
AOLSFAQ=http://wombat.san-francisco.ca.us/cgi-bin/fom

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (GNU/Linux)

iD8DBQFBXaoHhVcNCxZ5ID8RAqCOAJ9G4Sj5dAS+0IoIpY3kf64SsPt4OgCfRFw8
W60xtsNDp4oagNSYjUBisZo=
=ENhP
-----END PGP SIGNATURE-----
 
A

A. Sinan Unur

A. Sinan Unur ([email protected]) wrote on MMMMXLIX September
MCMXCIII in <URL:news:[email protected]>:
!! > So to empty and process my array/stack I need to:
!! > while (scalar(@array)) {
!! > $_=pop(@array);
!! > ...
!! > }
!!
!! You could do
!!
!! use strict;
!! use warnings;
!!
!! my @array = ('hello', '');
!!
!! while(@array and my ($x) = pop @array) {
!! print "Popped: [$x]\n";
!! }
!!
!! __END__

Tricky. And not very nice to post this without explaining why this
works. (It won't work if you remove the parens around the '$x').

Well, I know you know why it works, but I also see the point of your
remark, so here it goes. Consider the condition in the while statement:

@array and my ($x) = pop @array

@array in this context returns the number of elements in the array. Only if
the number of elements in @array is greater than zero will the right hand
side above will be evaulated.

my ($x) = pop @array;

pops an element off @array, puts it in $x, and returns the single element
list ($x). Hence, the RHS is always true, if @array has any elements. This
way, the while-loop does not prematurely abort if one of the elements in
the list is undefined.

I am really not suggesting this as a good solution. In fact, I would
probably be inclined to use the first answer I posted:

while (@array) {
my $x = pop @array;
# do something with $x
}

I only posted the solution above to show how the test can be constructed as
a single compund statement that does not abort in the middle if one of the
list elements is undefined.

Hope this is clearer and I did not make too many errors above.

Sinan.
 
J

Jeff 'japhy' Pinyan

So to empty and process my array/stack I need to:
while (scalar(@array)) {
$_=pop(@array);
...
}

You could do

use strict;
use warnings;

my @array = ('hello', '');

while(@array and my ($x) = pop @array) {
print "Popped: [$x]\n";
}

No, he couldn't. It *still* breaks out of the while conditional when
pop() returns a false element.

--
Jeff "japhy" Pinyan % How can we ever be the sold short or
RPI Acacia Brother #734 % the cheated, we who for every service
Senior Dean, Fall 2004 % have long ago been overpaid?
RPI Corporation Secretary %
http://japhy.perlmonk.org/ % -- Meister Eckhart
 
J

Jeff 'japhy' Pinyan

So to empty and process my array/stack I need to:
while (scalar(@array)) {
$_=pop(@array);
...
}

You could do

use strict;
use warnings;

my @array = ('hello', '');

while(@array and my ($x) = pop @array) {
print "Popped: [$x]\n";
}

Sorry, I jumped the gun. I didn't notice the parentheses around $x.

Nice trick.

--
Jeff "japhy" Pinyan % How can we ever be the sold short or
RPI Acacia Brother #734 % the cheated, we who for every service
Senior Dean, Fall 2004 % have long ago been overpaid?
RPI Corporation Secretary %
http://japhy.perlmonk.org/ % -- Meister Eckhart
 
A

A. Sinan Unur

use strict;
use warnings;

my @array = ('hello', '');

while(@array and my ($x) = pop @array) {
print "Popped: [$x]\n";
}

Sorry, I jumped the gun. I didn't notice the parentheses around $x.

Don't worry about it. As Abigail also noted, I should have explained why &
how and pointed out the necessity of the paranthesses around the $x.
Otherwise, it is easy to miss them.
Nice trick.

Thanks.

Sinan.
 
A

A. Sinan Unur

A. Sinan Unur ([email protected]) wrote on MMMML September
MCMXCIII in <URL:news:[email protected]>:
}} my ($x) = pop @array;
}}
}} pops an element off @array, puts it in $x, and returns the single
}} element list ($x). Hence, the RHS is always true, if @array has
}} any elements.
Eh, no. The assignment is done in scalar context,

Which is why the RHS is always 1, i.e. true. I am sorry if I wasn't clear.

Sinan.
 
C

Charles DeRykus

A. Sinan Unur ([email protected]) wrote on MMMML September
MCMXCIII in <URL:}} }}
....

Eh, no. The assignment is done in scalar context, and you can't have
lists in scalar context. A list assignment in scalar context returns
the number of elements on the right hand side of the assignment. And
that, in this case, is always 1.

This is way a trick like:

my $count = () = $str =~ /foo/g;

works.

Could this:

"A list assignment in scalar context returns the number of elements
on the right hand side of the assignment."

be better phrased:

A list assignment in scalar context can be special cased
to return the number of elements on the right hand side of
the assignment, which is why the trick below works:

my $count = () = (""); # count= 1

However an ordinary list assignment in scalar context returns
the final comma operand , e.g.

my $count = (1,2); # count = 2

?
 
P

Paul Lalli

Charles DeRykus said:
Could this:

"A list assignment in scalar context returns the number of elements
on the right hand side of the assignment."

be better phrased:

A list assignment in scalar context can be special cased
to return the number of elements on the right hand side of
the assignment, which is why the trick below works:

my $count = () = (""); # count= 1

However an ordinary list assignment in scalar context returns
the final comma operand , e.g.

my $count = (1,2); # count = 2
?

No, because this isn't a list assignment. By definition, a list
assignment is assigning something to a list. Nothing is being assigned
to a list here. More to the point, there is no "list" in that
expression. There is a scalar being assigned the return value of the
comma operator.

In the first example, the phrase "list assignment in scalar context"
refers to the return value of the assignment expression itself. All
expressions and statements return some sort of value, even those
expressions which themselves assign values.

Paul Lalli
 
B

Ben Morrow

Quoth "Paul Lalli said:
No, because this isn't a list assignment. By definition, a list
assignment is assigning something to a list. Nothing is being assigned
to a list here.

This is all true.
More to the point, there is no "list" in that
expression. There is a scalar being assigned the return value of the
comma operator.

This, however, is not. The comma operator constructs lists; a list
evaluated in scalar context evaluates all its members but the last in
void context and the last in scalar context, which is then the list's
value.

perl -MO=Graph,-dot -e'my $count = (1,2)' | dot -Tps

produces output the pertinant parts of which look somewhat like:

leave(LISTOP) { # end scope

enter(OP) # start scope
nextstate(COP) # start a statement
sassign(BINOP) { # scalar assignment

list(LISTOP) { # build a list

pushmark(OP) # mark the start of the list on the stack
null(OP) # the optimizer has deleted the 1
const(SVOP) # refers to an IV, the 2
}
padsv(OP) # retreives $count to assign into
}
}

(these op trees are executed inside-out, so the execution order is

enter, nextstate, pushmark, null, const, list, padsv, sassign, leave

as you would expect)

Note the 'list(LISTOP)': perl is building a list and then performing a
scalar assignment of that list to $count.

Ben
 
P

Paul Lalli

Ben said:
The comma operator constructs lists; a list
evaluated in scalar context evaluates all its members but the last in
void context and the last in scalar context, which is then the list's
value.

So the Perl FAQ is wrong? I refer you to the array vs list perlfaq:

As a side note, there's no such thing as a list in scalar
context. When you say

$scalar = (2, 5, 7, 9);

you're using the comma operator in scalar context, so it
uses the scalar comma operator. There never was a list
there at all! This causes the last value to be returned: 9.

And likewise, perldoc perlop is also wrong?

Binary "," is the comma operator. In scalar context it
evaluates its left argument, throws that value away, then
evaluates its right argument and returns that value. This
is just like C's comma operator.

perl -MO=Graph,-dot -e'my $count = (1,2)' | dot -Tps

I admit to having no idea what any of the above arguments, nor the below
output mean. I will research tomorrow after a night's rest.

Paul Lalli
 
B

Ben Morrow

Quoth Paul Lalli said:
So the Perl FAQ is wrong? I refer you to the array vs list perlfaq:
And likewise, perldoc perlop is also wrong?

Hmmm.... at the risk of sounding arrogant :), yes, I would say so. Perl
always compiles the comma operator into the same ops: those which build
a list. As a list-in-scalar-context evaluates to its last entry, the
two operators described in perlop will always produce the same results
as the one perl actually uses, making this perhaps an irrelevant
distinction; however, I would say that what actually happens is simpler
and (for me, at least) easier to understand than saying there are two
different comma operators. For example, take

sub foo {
return (1, 2, 3);
}

.. When this sub is compiled, perl cannot know what context it will be
called in, so how can it know 'which' comma operator you mean?
I admit to having no idea what any of the above arguments, nor the below
output mean. I will research tomorrow after a night's rest.

:)

B::Graph produces a graph showing the optree perl generates for a given
piece of code. What I typed below is a very simplified diagram showing
the structure of the output for that piece of code.

Ben
 
B

Brian McCauley

Ben said:
Hmmm.... at the risk of sounding arrogant :), yes, I would say so. Perl
always compiles the comma operator into the same ops: those which build
a list. As a list-in-scalar-context evaluates to its last entry, the
two operators described in perlop will always produce the same results
as the one perl actually uses, making this perhaps an irrelevant
distinction;

OK I'd like to address this without digging into at the internals of how
the Perl compiler is implemented and looking only at the observable
behaviour of Perl programs that would behave differently under the two
cases.

require AtExit;

sub foo {
my $msg = shift;
print "+$msg";
AtExit->new(sub{ print "-$msg"});
}

my $q = (foo(1),foo(2),foo(3),foo(4));
print "|";

The "two different comma operators" model predicts '+1-1+2-2+3-3+4|-4'.

The "last element of list" model predicts '+1+2+3+4-1-2-3|-4' or
'+1+2+3+4-3-2-1|-4'

On Perl 5.8.4 I get '+1-1+2-2+3-3+4|-4'.
 

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
474,161
Messages
2,570,892
Members
47,427
Latest member
HildredDic

Latest Threads

Top