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

Dear all,

Could someone please enlighten me why the below code

```use strict;
use warnings;

use Data::Dumper;

sub a{
return(undef, undef);
}

my(\$x, \$y);
if((\$x, \$y) = a() ){
print "OK1\n";
}

if((undef, undef) = a() ){
print "OK2\n";
}

if(a()){
print "OK3\n";
}

if(undef, undef){
print "OK4\n";
}
prints
```OK1
OK2
I absolutely expected it to print nothing at all. I mean I expect (\$x, \$y) = a() and above all (undef, undef) = a() to evaluate to false in boolean context. What do I miss here?

Replies are listed 'Best First'.
Re: Can't understand function returning undefs
by ikegami (Pope) on Sep 24, 2010 at 21:50 UTC

Just like "FOO + BAR" doesn't return "FOO" or "BAR", "FOO = BAR" doesn't necessarily return "FOO" or "BAR". A list assignment in scalar context returns the number of values returned by its RHS.

In detail,

"(\$x,\$y) = a()" is a list assignment, and it is being evaluated in scalar context (from the if()). A list assignment in scalar context returns the number of values returned by its RHS. In this case, that's 2.

"(undef,undef) = a()" is a list assignment, and it is being evaluated in scalar context (from the if()). A list assignment in scalar context returns the number of values returned by its RHS. In this case, that's 2.

"a()" is a function call, and it is being evaluated in scalar context (from the if()). A function called in scalar context evaluates its return expression in scalar context, so "undef, undef" is evaluated in scalar context. The list/comma operator in scalar context evaluates each operand in turn and returns the last value. In this case, that's undef.

"undef, undef" is being evaluated in scalar context (from the if()). The list/comma operator in scalar context evaluates each operand in turn and returns the last value. In this case, that's undef.

Retracted after bitter tirade by ikegami. Thanks for setting me straight in such a civil manner.

This is closely related to the concept of the default input operator

What are you talking about???

• \$_ is not an operator, at least no more so than \$x.
• Some functions default to using \$_ as an argument, but that is unrelated to this thread.
• \$_ has nothing to with input.
• How can an input operator have anything to do with this?

And the rest of the post is no better. So many errors!

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

This evaluates what a() returns, in scalar context. \$_ gets the last value returned by a(). In this case, \$_ is 3, or True if evaluated in Boolean context. If you tested \$x = a(), you'd get the same True result, with \$x equal to 3.

• That code doesn't provide enough information to determine in which context a() is evaluated. If anything, void context is implied.
• Nothing is assigned to \$_.
• If a() is evaluated in scalar context, then it makes no sense to talk about the last value it returns as it only returns one.

sub a{ return 1, 2, 0 }  a();

\$_ gets the last value returned by a(), as before. In this case, \$_ is 0 in scalar context, or False in Boolean context!

• Nothing is assigned to \$_.
• The same value is returned by the comma operator in both "boolean context" and scalar context.

@a = (undef, undef); @a;

This array is evaluated in scalar context because we haven't done anything to force list context. An array, evaluated in scalar context, is always the number of elements it contains.

• That code doesn't provide enough information to determine in which context a() is evaluated. If anything, void context is implied.
• There is no default context.

sub a{ return 1, 2, 0 } (\$x,\$y) = a();

We're still evaluating what a() returns, but here we've forced list context. That means that \$_ is assigned the number of elements in the list returned, not the elements. It doesn't matter what a() returns -- if it returns one or more elements, \$_ will be set to non-zero, or True in Boolean context.

• List context isn't being forced, if there is such a thing.
• Nothing is assigned to \$_, so most of that is just nonsense.
• The same value is returned by the list assignment operator in both "boolean context" and scalar context.

sub a{ return 1, 2, 0 }  @arr = a();

Exactly the same as above.

• List context isn't being forced, if there is such a thing.
• Nothing is assigned to \$_, so most of that is just nonsense.
• The same value is returned by the list assignment operator in both "boolean context" and scalar context.

(undef, undef);

An array is a container for a list. This is NOT an array, and we haven't done anything to force list context, so we have a list of scalars evaluated in scalar context. \$_ is set to the last element, which is undef -- or False in Boolean context.

• There is no default context.
• That code doesn't provide enough information to determine in which context a() is evaluated. If anything, void context is implied.
• Nothing is assigned to \$_.
• The same value is returned by the comma operator in both "boolean context" and scalar context.

sub a { return undef, undef } (\$x, \$y) = a(); if(not \$x && not \$y) { print "False\n" }

I think this is closer to what you're looking for. Whenever you don't specifically lay out the condition you are testing, you are probably testing \$_.

No, it's not what he wants.

• It doesn't loop.
• The condition of the "if" statement relies on incorrect assumptions about precedence.
• A truth test is two levels removed from optiomal. (A defined test would be better, but testing whether the iterator returned anything at all would be best.)

I hope this helps.

Pure harm. Good thing the formatting makes it unreadable.

Re: Can't understand function returning undefs
by jettero (Monsignor) on Sep 24, 2010 at 20:21 UTC
```if( ()=(0,0) ) {
print "sometimes you're counting the things in the list and getting
+2.\n"

}

if( (0,0) ) {
print "sometimes you're applying the comma operator and getting und
+ef (last)\n";
}

if is going to boolean test, so it's rather like this:

```use Data::Dumper;
print Dumper({ test1=>scalar( 7,13 ), test2=>scalar( ()=(7,13) ) }), "
+\n";

Thanks. Not that I like this behavior but I think I'll have to live with it.

But if we are at it. My problem is that I have a function that returns two values when data is available to it and when no data remained it returns undef.

```sub recv_data{
return(\$stuff1, \$stuff2);
} else {
return;
}
}
What I would like to do is to call this function in a while until all data is consumed. I tried to do this first by
```while((\$x, \$y) = recv_data){
...
}
which failed due to the above reasons (i.e., the while block always executed since (\$x, \$y) = recv_data always evaluates to true even if the function returns undef).

I still have the option to write

```while(1){
my(\$x, \$y) = recv_data;
last unless defined \$x;
...
}
but I fail to see this as elegant.

How to organize this code so that I obtain the required behavior in an elegant and readable way?

```sub recv_data{
return(\$stuff1, \$stuff2);
} else {
return;
}
}

The function in your example returns an empty list, not undef, in list context when there is no more data available.

If your real function actually returns undef in list context (which is 'supplied' to the function by the  (\$x, \$y) sub-expression in your example code), then the list will always have at least a single item (i.e., undef) and will always evaluate as true; only the empty list or array is false. See the code below for the difference between
return;
and
return undef;

```>perl -le
"use warnings FATAL => 'all';
use strict;
;
my @pairs1 = qw(1 2 3 4);
;
sub S1 {
return if not @pairs1;
return pop @pairs1, pop @pairs1;
}
;
my (\$x, \$y);
while ((\$x, \$y) = S1()) {
print qq{\$x \$y};
}
;
my @pairs2 = qw(5 6 7 8);
;
sub S2 {
return undef if not @pairs2;
return pop @pairs2, pop @pairs2;
}
;
while ((\$x, \$y) = S2()) {
print qq{\$x \$y};
}
"
4 3
2 1
8 7
6 5
Use of uninitialized value \$x in concatenation (.) or string at ...
```while(  defined( ( (\$x,\$y)= recv_data() )[0] )  )

But I'd rather do that like:

```my( \$x, \$y )= recv_data();
while(  defined \$x  ) {
...
( \$x, \$y )= recv_data();
}

- tye

But if we are at it. My problem is that I have a function that returns two values when data is available to it and when no data remained it returns undef.

It should return an empty list when no data remains. Compare

```my @a = qw( a b c d );
my \$i = sub { @a ? splice(@a, 0, 2) : () };
while (my (\$x,\$y) = \$i->()) {
print("\$x:\$y\n");
}
with
```my @a = qw( a b c d );
my \$i = sub { @a ? splice(@a, 0, 2) : (undef,undef) };
while (my (\$x,\$y) = \$i->()) {
print("\$x:\$y\n");
}

Update: Added missing semicolons.

Re: Can't understand function returning undefs
by JavaFan (Canon) on Sep 24, 2010 at 21:40 UTC
You're expecting a true/false value from your function a(). However, the expression in your if statement isn't a(), it's a list assignment. And, in scalar context, list assignment returns the number of elements on the RHS of the assignment. So, if a() returns 2 elements, the assignment returns 2 (changing the variables on the LHS is a mere side-effect of the assignment). It's only the quantity of the elements returned by a() that matters, not their value.
Here is what drives me crazy:
```if(undef, undef){
print "OK1\n";
}

if( (undef, undef) ){
print "OK2\n";
}

my @a = (undef, undef);
if(@a){
print "OK3\n";
}
```  if (undef, undef) { # An extra set of parens doesn't matter.