print scalar (1,2,3);;
Useless use of a constant in void context at (eval 18) line 1, <STDIN>
+ line 16.
3
And map and grep each return lists ...
...except, when they find their return context is SCALAR they chose not to return a list, but instead they return a scalar, which happens to be the size of the list they would have returned had they found themselves in a list context.
...except also when they find themselves in a void context, in which case they chose not to return anything at all.
It mostly a matter of words, but I think it is wrong to say "map and grep each return lists", when like any other perl function they can chose whether to return a list, a scalar or nothing at all depending upon the context in which they are called.
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] |
You do a good job of showing how the meme is seductive. Thanks.
Let's start with the original statement, verbatum, which is not picking on
FunkyMonk since this is not even close to an unusual phrasing of the
oft-repeated meme:
A slice returns a list and assigning a list to a scalar will just assign the
last item in the list to the scalar.
That (somehwat implied) logical argument can be broken down into several pieces:
- A slice returns a list1
- Assigning a list2 to a scalar will just assign the last
item of the list3 to the scalar
- Therefore, a slice in scalar context returns the last value from the
slice
Now, for item 3 to make logical sense, the meaning of item 2 must be stronger
than how it might be interpretted on its own. So it would be
clearer to upgrade item 2 via s/a list/any list/ and/or
s/will/will always/.
Hm. Seems to me that a list in a scalar context does return the last item:
print scalar (1,2,3);;
Useless use of a constant in void context at (eval 18) line 1, <STDIN>
+ line 16.
3
Certainly. It also seems to me that a slice returns a list. It also seems to
me that grep, in precisely the same way, "returns a list".
Therefore, it should seem to me that grep in scalar context returns the last
item (but, of course, it doesn't).
You (as has become quite typical, when people try to defend this flawed meme)
make an argument about how you can claim that "grep doesn't
really 'return a list'". But go ask some average Perl
programmer you run into "Does grep return a list?". If they immediately
respond "Well, not really", I'll be quite shocked. If they say as
you did, "No, that is wrong", I'll be even more shocked. But if so,
ask them if a slice returns a list. If they immediately respond "Oh, yes, of
course, always", then they are clearly a figment of your imagination. :)
A much better way to resolve the problems with this meme lies in quite a
different direction (and thanks for also demonstrating that, even though I've
gone over this many times over many years, there are no shortage of fine, very
wise monks who appear to have missed it). So, back to our 3 statements.
Consider "2) Assigning a list2 to a scalar will just assign the
last item of the list3 to the scalar". As you so aptly
demonstrated, what "list2" means here is better termed "list
literal" or, perhaps more accurately but certainly more awkwardly termed "the
use of the comma operator within parentheses". That is, the prototypical
construct ('a','b','c').
Yes, a (any) "list literal" (often just referred to as just "a list" in many
situations) certainly (always) returns some "last item" when used in
a scalar context. So, in "1) A slice returns a list1", do we mean
that a slice returns a "list literal"? Of course not! How could a slice
"return a use of the comma operator"? You can't even argue that a hash slice
gets compiled into the same code as ( $h['a'], $h['b'], $h['c'] ) does,
simply because it doesn't.
A slice returns a "list of scalar values" (at least when used in a
list context). So "list1" means "a list of scalar values" (perhaps
with some extra qualifiers, or perhaps not, depending on one's point of view
and perhaps even on which version of Perl is being discussed, etc.).
So "list1" and "list2" actually mean two quite different
(but related) things. You certainly can't reasonably argue that
"list1" means "list literal". But perhaps you want to argue the
other direction, that is, to claim that "Assigning a list of scalar
values to a scalar will just assign the last item of the list3
to the scalar".
Well, that would certainly be rather awkward to argue. But I'll also note
an extra wrinkle you'd trip over if you did try to do that. Consider the
following:
sub f { return( 'a', 'b', reverse(1..3) ); }
my @list = f();
my $scalar = f();
We see that @list gets assigned a list of scalar values [namely,
( 'a', 'b', 3, 2, 1 )]. So, if "Assigning a list of scalar
values to a scalar will just assign the last item of the list3
to the scalar", then surely $scalar gets set to the last item in that
list of scalar values, namely 1. But no, $scalar gets
set to "321".
This is because "list2" means "list literal" and "list3"
also doesn't mean "list of scalar values"; "list3" means "the list
of expressions that have been separated by commas". What gets
assigned to $scalar is the value of reverse(1..3), interpretted
in a scalar context. reverse(1..3) is the last item in the list of
expressions that were separated by commas.
So what is true is that:
A list literal (use of the comma operator within parentheses) in a scalar
context returns the value of the last (comma-separated) expression, itself
interpretted in a scalar context.
Surely it is clear that this fact has very little to do with what a slice
(array slice, hash slice, or list slice) returns in a scalar context.
And that is why the quoted meme is seriously flawed (despite producing a
correct prediction in the case of a slice -- and wrong predictions in cases
including grep).
Now, as for the competing meme that is used to counter the above meme, namely:
"there is no such thing as 'a list in scalar context'"... I believe
that it presents an important concept. Unfortunately, in an attempt to state
this concept forcefully, it over-states it and thus is actually an
incorrect statement.
As you correctly pointed out, there actually are several cases where Perl
produces a list of scalar values (on the stack) despite this production being
done "in a scalar context". But these cases are still "the exception" more
than "the rule".
Perhaps a better phrasing of this competing meme would be (to paraphrase
another famous phrase) "Perl abhors a list in a scalar context". Or, more
clearly, "Perl rarely bothers to produce a list (of scalar values)
when working in a scalar context".
But slices and grep are both examples where Perl (at least some versions of
Perl) will do exactly that: produce a list of scalar values (on the stack)
despite that list being produced "in a scalar context".
But we should also note that this "throw away most of the list and just return
one scalar when confronted with a scalar context" is not automatic. The code
to do that was missing for the case of a (hash(?)) slice prior to me submitted
a patch many years ago. And Perl could dump core as a result. Every place
that produces "a list in a scalar context" has to also have its own code added
for taking care of throwing away most of the list. (Though Perl does defend
itself against sloppy XS code, not requiring each XS function to take
care of this situation itself.)
That is, there is, in fact, no general "just return the last item of the list"
code in Perl. There are several specific cases of such code (as well
as several specific cases of code that returns something other than the last
item).
Finally, the moral of this story is:
When you see 'list' being used in reference to Perl, it can mean any of quite a few different things. And this is despite the fact that "scalar", "scalar context", and "list context" are each pretty preciesly defined for Perl.
And I didn't even mention that tr/.../.../ and regex character classes are each documented to use a "list" of characters and \w is even said to "generate a list". (:
| [reply] [d/l] [select] |
| [reply] |
scalar (1, 2, 3);
is the comma operator in scalar context. Of which man perlop says:
Binary "," is the comma operator. In scalar context it evaluates its
left argument, throws that value away, then evaluates its right
argument and returns that value. This is just like C's comma operator.
except, when they find their return context is SCALAR they chose not to return a list, but instead they return a scalar
A feat not reserved for map and grep, but shared by every operator and function in Perl, including, without a single exception, all user defined functions. Anything that is in non-void scalar context will return exactly one value. And nothing will ever be returned in void context.
It mostly a matter of words, but I think it is wrong to say "map and grep each return lists", when like any other perl function they can chose whether to return a list, a scalar or nothing at all depending upon the context in which they are called.
You are mostly right. Except that a function or operator cannot chose whether to return a list, a scalar or nothing at all. It's the context that makes the choice - not the function.
| [reply] [d/l] |