jdklueber has asked for the wisdom of the Perl Monks concerning the following question:
O Monks-
I thought I knew what I was doing. I thought that 7 years of coding Perl would've taught me most of the tricks... or, at least, brought me the insight to explain this little puzzle. A coworker brought this to my attention:
Given an array...
@foo = (1,2,3);
This statement
print "@foo[1]\n";
Yields
2
I thought that this would be invalid Perl, yet it works. Given that you declare @foo, it even works under strict (though warnings will generate a message like "Scalar value @foo[1] better written as $foo[1] at C:\WINDOWS\DESKTOP\FOO.PL line 6.").
Anyone have an explanation of this behavior?
--
Jason Klueber
ookami@insightbb.com
/(bb)|[^b]{2}/
--Shakespeare
Fixed square brackets - dvergin 2003-08-04
Re: @array[1] is valid??
by allolex (Curate) on Aug 04, 2003 at 19:01 UTC
|
That's a slice you've got there. From the Camel Book:
"Saying @foo[1] when you mean $foo[1]. The @foo[1] reference is an array slice, meaning an array consisting of the single element $foo[1]. Sometimes this doesn't make any difference, as in:
print "the answer is @foo[1]\n";
but it makes a big difference for things like:
@foo[1] = <STDIN>;
which will slurp up all the rest of STDIN, assign the first line to @foo[1], and discard everything else. This is probably not what you intended. Get into the habit of thinking that $ means a single value, while @ means a list of values, and you'll do okay."
--
Allolex
| [reply] [d/l] [select] |
Re: @array[1] is valid??
by halley (Prior) on Aug 04, 2003 at 18:56 UTC
|
This is a one-element slice, which is better written as suggested. To explore slices, try:
@foo = qw(zero one two three four five);
print $_, $/ foreach (@foo[2..4]);
print $/;
print $_, $/ foreach (@foo[1,3,5]);
-- [ e d @ h a l l e y . c c ] | [reply] [d/l] |
Re: @array[1] is valid??
by dvergin (Monsignor) on Aug 04, 2003 at 19:02 UTC
|
You are printing a single-element array slice. Perhaps this will make more clear what is happening.
my @foo = (1,2,3);
print "@foo[1,2]\n"; #prints: 2 3
------------------------------------------------------------
"Perl is a mess
and that's good because the
problem space is also a mess." - Larry Wall
| [reply] [d/l] |
Re: @array[1] is valid??
by CountZero (Bishop) on Aug 04, 2003 at 19:04 UTC
|
$foo[1] returns you a scalar and @foo[1] returns you a one element list. If you do it in a context which is sensible to being in scalar or list context, it might bite you, hence the message given by warnings. CountZero "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law
| [reply] [d/l] [select] |
Re: @array[1] is valid??
by Abigail-II (Bishop) on Aug 04, 2003 at 22:40 UTC
|
As other have explained, it's a one element slice. Unfortunally, if you use it like this, Perl will issue a
warning. I don't think it's right that Perl should give
this warning; why should a one element slice trigger a
warning when two, three, four, ..., or even a zero element
slice don't? Furthermore, in most cases @foo 1
is used in rvalue context, where it won't matter anyway.
The only place where it might go wrong, is where you use @foo 1 in lvalue context,
and the RHS of the assignment returns different things in
list and scalar context.
But that's a rare case. In a more common case, which more
often goes wrong is my ($foo) vs my $foo.
But Perl doesn't warn there.
And considering that in perl6, @foo 1 is the
right way to address a single element (what's perl6 syntax
for a one element slice?), I think that warning ought to
removed from Perl.
I've once send that in as a wish to p5p, but it was ignored.
Abigail | [reply] |
|
| [reply] |
|
#!/usr/bin/perl
use strict;
no warnings;
my (@firstkey, @numberofkeys);
my @list = qw /foo housekey blah carkey baz monkey/;
@firstkey [0] = grep {/key$/} @list;
$numberofkeys [0] = grep {/key$/} @list;
print "@firstkey\n";
print "@numberofkeys\n";
__END__
housekey
3
And yes, there are a million different ways to write this
code, but that's not the point.
But I can't think of a case where using @array [0]
in non-lvalue context could return something else than
$array [0].
Abigail
| [reply] [d/l] [select] |
|
|
|
Re: @array[1] is valid??
by jdklueber (Beadle) on Aug 05, 2003 at 13:53 UTC
|
D'oh! I looked in my Camel book, but completely glossed over array slices... and since I've never once had to use them, I didn't realize that was the notation for it. Thanks everyone for filling in this blind spot for me!
--
Jason Klueber
ookami@insightbb.com
/(bb)|^b{2}/
--Shakespeare
| [reply] |
|
|