The number of values in a list can only be determined by iterating over its values, or converting it to an array. Assigning it to a scalar won't return the items count:
my $n = ('a', 'b', 'c'); # $n = 'c'
There's an "empty parentheses" idiom, that can be used to get the number of elements:
my $n = () = ('a', 'b', 'c'); # $n = 3
Is it equivalent internally to
my $n = @{[ 'a', 'b', 'c' ]};
?
The two items you showed are not equivalent. But they have the same final result;
my $n = @{[ 'a', 'b', 'c' ]};
Here you create an anonymous array [ 'a', 'b', 'c' ]
, then dereference it and take the count of members. The creation of the array provides a list context to the comma operators in the statement.
my $n = () = ('a', 'b', 'c');
Here we use the infamous "goatse operator". The list ('a', 'b', 'c')
is assigned to an empty list () = ('a', 'b', 'c');
. The result of the list assignment is assigned to $n
. List assignment returns the number of items on the right hand side of the assignment in scalar context (in list context, you get the list of values assigned to).
This is an interesting implementation detail: Does the assignment to an empty list create an (unnecessary) anonymous array?
There are two ways of answering this question: First, The Right Way: Try to figure out how this might be handled in the source. Is there a special case for assignment to an empty list evaluated in scalar context?
Being the lazy and ignorant type, I chose to use Benchmark:
#!/usr/bin/perl
use strict; use warnings;
use Benchmark qw( cmpthese );
cmpthese -5, {
goatse => sub { my $n = () = 'A' .. 'Z' },
anon => sub { my $n = @{[ 'A' .. 'Z' ]}},
};
I ran the benchmark a bunch of times, and the assignment to empty list had a slight advantage in all cases. If the difference were purely random, the probability of observing 10 timings all in favor of goatse is less than 0.1%, so I am assuming there is some kind of short circuit.
On the other hand, as running the benchmark @daotoad posted in the comments, probably gives a more complete picture:
#!/usr/bin/perl
use strict; use warnings;
use Benchmark qw( cmpthese );
use constant START => 1;
use constant STOP => 1000;
my $start = START;
my $stop = STOP;
cmpthese -5, {
anon => sub { my $n = @{[ $start .. $stop ]}},
goatse => sub { my $n = () = $start .. $stop },
canon => sub { my $n = @{[ START .. STOP ]}},
cgoatse => sub { my $n = () = START .. STOP },
};
Typical results on my machine (Windows XP Pro SP3, Core 2 Duo, 2 Gb memory, ActiveState perl
5.10.1.1006):
Rate anon cgoatse goatse canon anon 5207/s -- -45% -49% -51% cgoatse 9522/s 83% -- -7% -10% goatse 10201/s 96% 7% -- -4% canon 10636/s 104% 12% 4% --
And, with:
use constant START => 'AAAA';
use constant STOP => 'ZZZZ';
the results are:
Rate anon goatse cgoatse canon anon 1.73/s -- -12% -16% -17% goatse 1.98/s 14% -- -4% -5% cgoatse 2.06/s 19% 4% -- -1% canon 2.08/s 20% 5% 1% --
If in doubt, use my $n = () = ...;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With