[comp.lang.perl] null? or not null?

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (01/20/91)

In article <YbZGbb600VpQ82Jl1T@andrew.cmu.edu> rm55+@andrew.cmu.edu (Rudolph T. Maceyko) writes:
: while (($a,$b) = (&function)[7,8]) {
: 
: My problem is that the condition is always true!
: ...
: So how do I do what I want to do without using "dummy" variables like
: this:
: 
: while (($x,$y,$z,$a,$b) = &function) {

There's More Than One Way To Do It:

    while (($a,$b) = grep(defined, (&function)[7,8]))

    while (($a,$b) = (&function)[7,8], defined $a)

    while (grep(defined, ($a,$b) = (&function)[7,8]))

    while (join(' ', ($a,$b) = (&function)[7,8]))

If $a will always be true on successful return:

    while (($a,$b) = (&function)[7,8], $a)

    while ((($a,$b) = (&function)[7,8])[0])

Larry

rm55+@andrew.cmu.edu (Rudolph T. Maceyko) (01/20/91)

flee@cs.psu.edu (Felix Lee) writes:
> > print 2 if ($a,$b) = undef;               # prints 2 -- why?
> 
> "undef" is not a null list.  "()" is a null list.  "undef" is the same
> as "(undef)".  If you try

That's true, and I see why the assignment of "undef" to the list
returns true, but I still would like the the following while loop to
terminate if the function returns "()" (not "undef," as I stated
previously) instead of iterating indefinitely.

while (($a,$b) = (&function())[7,8]) {
 ...
}

I understand that "mentioning" non-existent array elements causes
their creation, but is that entirely necessary when the array is empty
and only referred to?

Unless it causes trouble that I don't forsee, I would consider
"ignoring" such array slices of "()" both a feature and an
optimization.  It's a feature because it makes my scripts work ;-> and
an optimization because creating new elements for the null list in
this case accomplishes nothing.

References to arrays (shift, pop) apparently always ignore null
elements (while references to lists [for, grep] do not), and
conditionality is apparently processed as a list (in an "array"
context).  Hmmm....  

A kludge which does what I want is:

sub function { (); }

while (($a,$b) = (@_ = &function())[7,8], @_) {
  print "yes\n";
}

but that involves the extra assignment and testing.  Do I have to live
with the kludge, or am I talking about a viable addition to the
language?

Rudy

+---------+
: +-----+ : Rudy Maceyko
: : +-+ : : rm55+@andrew.cmu.edu
: : : +-+ : rtmst@cis.pitt.edu
+-+ +-+-+-+ 

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (01/20/91)

In article <obaCBy600VozM6l0pF@andrew.cmu.edu> rm55+@andrew.cmu.edu (Rudolph T. Maceyko) writes:
: flee@cs.psu.edu (Felix Lee) writes:
: > > print 2 if ($a,$b) = undef;               # prints 2 -- why?
: > 
: > "undef" is not a null list.  "()" is a null list.  "undef" is the same
: > as "(undef)".  If you try
: 
: That's true, and I see why the assignment of "undef" to the list
: returns true, but I still would like the the following while loop to
: terminate if the function returns "()" (not "undef," as I stated
: previously) instead of iterating indefinitely.
: 
: while (($a,$b) = (&function())[7,8]) {
:  ...
: }
: 
: I understand that "mentioning" non-existent array elements causes
: their creation, but is that entirely necessary when the array is empty
: and only referred to?

But it's not true that mentioning non-existent array elements causes
their creation.  That's not what's going on here.

: Unless it causes trouble that I don't forsee, I would consider
: "ignoring" such array slices of "()" both a feature and an
: optimization.  It's a feature because it makes my scripts work ;-> and
: an optimization because creating new elements for the null list in
: this case accomplishes nothing.

What it accomplishes is to prevent even greater confusion.  See below.

: References to arrays (shift, pop) apparently always ignore null
: elements (while references to lists [for, grep] do not),

I don't think this is true either.  If you shift an undefined element out
of an array, you get an undefined value.  Can you give an example of what
you mean?

: and conditionality is apparently processed as a list (in an "array"
: context).

Here we begin to get to the root of the problem.  Conditions are not
evaluated in an array context, but a scalar context.  The array assignment
in a scalar context returns the number of elements that were available
on the right-hand side of the assignment.  And the ()[] operator always
produces the number of values that you gave as subscripts.

What you seem to be asking for is for the ()[] operator to automatically squish
out any undefined values.  But that would be very confusing.  Suppose you
reversed the subscripts and said

	($a,$b) = (&function)[8,7]

Suppose further that &function returned (0..7).  The ()[] constructs a
two element list, the FIRST of which is undefined, and the second of which
is 7. 

If we allow automatic squishing by ()[], $a gets the value intended for $b,
and $b gets the undefined value.  This would be highly counterintuitive,
especially as the list gets longer.  Neither ()[] nor ordinary array slices
should produce lists of indeterminate length, because the position of the
elements may be important unless you explicitly feed to a function that
doesn't care, like grep.  But the slice can't tell that.  Even if I made
it so that it could tell, it would think that assignment to ($a,$b) cared
about positions, so that would be no help to you.

If slices did autosquishing, and %bar contained undefined values, then

    @foo{@keylist} = @bar{@keylist};

wouldn't work.

It might just be possible to make slices discard any *trailing* undefined
elements, but that might cause other surprises.  I'd have to think about
that a lot.

Alternately, it might be possible to make array assignment in a scalar
context not count any trailing undefined values on the RHS, but again,
that's a very dangerous kind of semantic change.

An undefined scalar value has two distinct functions as a placeholder
in a list.  The first is to keep subsequent defined values at the correct
position.  The second is as a trailing value to make sure the list stays the
length that is expected.  The question is whether we can sacrifice the second
function, and how much it gains us.  I'm not convinced.

Larry

rm55+@andrew.cmu.edu (Rudolph T. Maceyko) (01/21/91)

In article <11125@jpl-devvax.JPL.NASA.GOV> lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) writes:
>: References to arrays (shift, pop) apparently always ignore null
>: elements (while references to lists [for, grep] do not),
>
>I don't think this is true either.  If you shift an undefined element out
>of an array, you get an undefined value.  Can you give an example of what
>you mean?

That part shouldn't have been in there...  It was more-or-less thinking
"out loud."  It was really just a summary of the behavior of the
iterative operators and how they acted on such a list:

sub function { (); }

# prints nothing (really a function of while test)
@x = (&function())[7,8];
while (shift @x) { print "shift: yes\n"; }

# prints nothing (really a function of while test)
@x = (&function())[7,8];
while (pop @x) { print "pop: yes\n"; }

# prints twice
for ((&function())[7,8]) { print "for: yes\n"; }

# prints just once -- why?
grep(print, "grep: yes\n", (&function())[7,8]);

>It might just be possible to make slices discard any *trailing* undefined
>elements, but that might cause other surprises.  I'd have to think about
>that a lot.
>
>Alternately, it might be possible to make array assignment in a scalar
>context not count any trailing undefined values on the RHS, but again,
>that's a very dangerous kind of semantic change.

Doesn't PERL distinguish undefined variables from those whose values are
"undef?"  If so, an element of an array slice should have the value of the
requested element if it has one (could be undef), or remain undefined.

For the scalar context of list assignment, only those values (defined
or undefined) up to and including the last defined value can be counted
for the value of the expression, giving you a better picture of what
was available for assignment.

I THINK everything would be ok; I thought there was a difference
between being undefined and just having the value "undef."  The
following script prints both lines, no matter which of the two
assignments is used.

#($a,$b) = (1);
($a,$b) = (1,undef);
print '! defined $b', "\n" unless defined $b;
print '! $b', "\n" unless $b;

Also, interestingly, the following script

print $], "\n";

print(($a,$b,$c) + 0, "\n");

$b = 1;
print(($a,$b,$c) + 0, "\n");

$c = 1;
print(($a,$b,$c) + 0, "\n");


prints

$Header: perly.c,v 3.0.1.9 90/11/10 01:53:26 lwall Locked $
Patch level: 41

0
0
1

I realize that I could still be confused about this issue, and I appreciate
your time and effort in analyzing this situation.  I hope I'm not wasting
anyone's time, but I would like to resolve the issue.

Rudy

+---------+
: +-----+ : Rudy Maceyko
: : +-+ : : rm55+@andrew.cmu.edu
: : : +-+ : rtmst@cis.pitt.edu
+-+ +-+-+-+ 

allbery@NCoast.ORG (Brandon S. Allbery KB8JRR) (01/22/91)

As quoted from <wbaVF1y00VouEJ6EA8@andrew.cmu.edu> by rm55+@andrew.cmu.edu (Rudolph T. Maceyko):
+---------------
| # prints just once -- why?
| grep(print, "grep: yes\n", (&function())[7,8]);
+---------------

Because this unwinds to:

	print "grep: yes\n";
	print (&function())[7];
	print (&function())[8];

The syntax of grep is "grep operation list"; in this case, the operation is
"print" and the list is ("grep: yes\n", (&function())[7], (&function())[8]).

+---------------
| Doesn't PERL distinguish undefined variables from those whose values are
| "undef?"  If so, an element of an array slice should have the value of the
| requested element if it has one (could be undef), or remain undefined.
+---------------

No, "undef" means the undefined state.

+---------------
| following script prints both lines, no matter which of the two
| assignments is used.
| 
| #($a,$b) = (1);
| ($a,$b) = (1,undef);
| print '! defined $b', "\n" unless defined $b;
| print '! $b', "\n" unless $b;
+---------------

Correct:  since $b is not defined, (defined $b) is false and the first print
is executed.  Since the undefined value is treated as false (actually, as the
null string) in a conditional, the second print is executed.

+---------------
| print $], "\n";
| print(($a,$b,$c) + 0, "\n");
| $b = 1;
| print(($a,$b,$c) + 0, "\n");
| $c = 1;
| print(($a,$b,$c) + 0, "\n");
| 
| prints
| 
| $Header: perly.c,v 3.0.1.9 90/11/10 01:53:26 lwall Locked $
| Patch level: 41
| 
| 0
| 0
| 1
+---------------

Got me there; I'm not *that* much of a Perl guru.

++Brandon
-- 
Me: Brandon S. Allbery			    VHF/UHF: KB8JRR on 220, 2m, 440
Internet: allbery@NCoast.ORG		    Packet: KB8JRR @ WA8BXN
America OnLine: KB8JRR			    AMPR: KB8JRR.AmPR.ORG [44.70.4.88]
uunet!usenet.ins.cwru.edu!ncoast!allbery    Delphi: ALLBERY

tchrist@convex.COM (Tom Christiansen) (01/22/91)

From the keyboard of allbery@ncoast.ORG (Brandon S. Allbery KB8JRR):
:As quoted from <wbaVF1y00VouEJ6EA8@andrew.cmu.edu> by rm55+@andrew.cmu.edu (Rudolph T. Maceyko):
:| Doesn't PERL distinguish undefined variables from those whose values are
:| "undef?"  If so, an element of an array slice should have the value of the
:| requested element if it has one (could be undef), or remain undefined.
:+---------------
:
:No, "undef" means the undefined state.

Yes, Brandon's right, although bear in mind that if you do this:

    $foo{'bar'} = undef;

You now have a key ('bar') that will show up if you pull the
keys from %foo.  Merely its value is undefined.

:+---------------
:| print $], "\n";
:| print(($a,$b,$c) + 0, "\n");
:| $b = 1;
:| print(($a,$b,$c) + 0, "\n");
:| $c = 1;
:| print(($a,$b,$c) + 0, "\n");
:| 
:| prints
:| 
:| $Header: perly.c,v 3.0.1.9 90/11/10 01:53:26 lwall Locked $
:| Patch level: 41
:| 
:| 0
:| 0
:| 1
:+---------------
:
:Got me there; I'm not *that* much of a Perl guru.

(I may be mis-interpreting the question, but here's a shot.)

There are no arrays in the preceding statements, because you've added a 0
to your ($a,$b,$c) list, coercing a scalar context, so you no longer have
list contruction, but rather simply the comma operator.  So you take the
last value in the list.

--tom
--
"Hey, did you hear Stallman has replaced /vmunix with /vmunix.el?  Now
 he can finally have the whole O/S built-in to his editor like he
 always wanted!" --me (Tom Christiansen <tchrist@convex.com>)