# So you think you understand array and scalar contexts.

26 views

### Felix Lee

May 19, 1990, 11:43:45 AM5/19/90
to
Quick, what does the fragment below print? No fair running it first
and rationalizing afterwards.

%zero = ();
%one = ('a', 1);
%many = ('a', 1, 'b', 2, 'c', 3);

print "0-0\n" if !%zero;
print "0-1\n" if %zero;
print "0-2\n" if %zero == 0;
print "0-3\n" if %zero != 0;
print "0-4\n" if !keys(%zero);
print "0-5\n" if keys(%zero);
print "0-6\n" if keys(%zero) == 0;
print "0-7\n" if keys(%zero) != 0;

print "1-0\n" if !%one;
print "1-1\n" if %one;
print "1-2\n" if %one == 0;
print "1-3\n" if %one != 0;
print "1-4\n" if !keys(%one);
print "1-5\n" if keys(%one);
print "1-6\n" if keys(%one) == 0;
print "1-7\n" if keys(%one) != 0;

print "n-0\n" if !%many;
print "n-1\n" if %many;
print "n-2\n" if %many == 0;
print "n-3\n" if %many != 0;
print "n-4\n" if !keys(%many);
print "n-5\n" if keys(%many);
print "n-6\n" if keys(%many) == 0;
print "n-7\n" if keys(%many) != 0;
--
Felix Lee fl...@shire.cs.psu.edu *!psuvax1!flee

### Larry Wall

May 22, 1990, 12:38:11 PM5/22/90
to
In article <E==f!d...@cs.psu.edu> fl...@shire.cs.psu.edu (Felix Lee) writes:
: Quick, what does the fragment below print? No fair running it first
: and rationalizing afterwards.

What about WRITING it first and rationalizing it afterwords? :-)

: %zero = ();

: %one = ('a', 1);
: %many = ('a', 1, 'b', 2, 'c', 3);
:
: print "0-0\n" if !%zero;

TRUE
: print "0-1\n" if %zero;
FALSE
: print "0-2\n" if %zero == 0;
TRUE
: print "0-3\n" if %zero != 0;
FALSE

Those are easy if you know what scalar %array returns, and know that number
conversion ignores trailing garbage. (Scalar %array returns a string
of the form "\$entries/\$buckets", where \$buckets is always a power of two,
and \$entries is not the number of keys, but the number of buckets containing
at least one key. So currently a null %array returns "0/8". After the next
patch it will just return "0", by the way, just so you can say "if %zero".)

: print "0-4\n" if !keys(%zero);
TRUE
: print "0-5\n" if keys(%zero);
FALSE
: print "0-6\n" if keys(%zero) == 0;
TRUE
: print "0-7\n" if keys(%zero) != 0;
FALSE

keys currently always returns undef in a scalar context. And undef is FALSE
and equals 0. You might convince me that it should be otherwise.

: print "1-0\n" if !%one;
FALSE
: print "1-1\n" if %one;
TRUE
: print "1-2\n" if %one == 0;
FALSE
: print "1-3\n" if %one != 0;
TRUE
: print "1-4\n" if !keys(%one);
TRUE
: print "1-5\n" if keys(%one);
FALSE
: print "1-6\n" if keys(%one) == 0;
TRUE
: print "1-7\n" if keys(%one) != 0;
FALSE

These are fairly trivial, modulo the perpetually undeffed keys call.

: print "n-0\n" if !%many;
FALSE
: print "n-1\n" if %many;
TRUE
: print "n-2\n" if %many == 0;
FALSE
: print "n-3\n" if %many != 0;
TRUE
: print "n-4\n" if !keys(%many);
TRUE
: print "n-5\n" if keys(%many);
FALSE
: print "n-6\n" if keys(%many) == 0;
TRUE
: print "n-7\n" if keys(%many) != 0;
FALSE

Likewise these.

It's always hard to decide whether an array operator should return anything
useful in a scalar context, especially when you don't have anything useful
to return. In the case of keys, I could return a random element, which
makes little sense. Or I could return the number of keys, except that I'd
have to go through and count them, which I don't want to do.

Larry

### Felix Lee

May 22, 1990, 5:41:18 PM5/22/90
to
>Or I could return the number of keys, except that I'd have to go
>through and count them, which I don't want to do.

Isn't this just tbl_fill in the hash table structure? Well, a dbm
assoc may be a problem, but you have to deal with that when you use
%dbm in a scalar context anyway.

I feel like any array operation in a scalar context should return the
length, much like @a in a scalar context returns the length of a.
This may not always be useful ("sort" in a scalar context?) but it has
the virtue of being consistent with things like "split" and "grep".

Making this completely orthogonal would clash with the comma operator:
\$x = (3, 2, 1);
I'm sure there are people who depend on this behavior, right?

Here's a totally different idea. Why not give lists a different
delimiter, like square brackets? Keep parentheses the way they are
now, but square brackets can unambiguously say, "this is a list".

Subscripting and slicing fit in nicely with this syntax:
@y = ['a', 'b', 'c', 'd'] [1, 3];
\$x = @y;
And this can be extended easily to lists of lists and multiple
subscripts and multidimensional arrays.

Perl isn't about data types, but I can wish, can't I?

Maybe if some dialect of Icon or something ever has as much system
support as Perl does, I'll abandon the Perl bandwagon. Perl is the
BASIC of the '90s. :-)

@a=split(//,\$]);@b=split(//,"k ple th\nhroeaarcn.");\$k=\$#a=\$#b;@a=sort
grep(\$_.=\$k++,@a);print@b[substr(pop(@a),1,2)-\$#b]while(@a);