9
my $mind = ( 'a', 'little', 'confused' );

And it's because perldoc perlfaq4 explains the line above as follows (emphasis added):

Since you're assigning to a scalar, the righthand side is in scalar context. The comma operator (yes, it's an operator!) in scalar context evaluates its lefthand side, throws away the result, and evaluates it's righthand side and returns the result. In effect, that list-lookalike assigns to $scalar it's rightmost value. Many people mess this up because they choose a list-lookalike whose last element is also the count they expect:

my $scalar = ( 1, 2, 3 );  # $scalar gets 3, accidentally

What I understand this to mean is that there is no such thing as a list in scalar context.

However, ikegami maintains that it "result[s] in a list operator, so it is a list literal."

So, is it a list or not?

Community
  • 1
  • 1
Zaid
  • 36,680
  • 16
  • 86
  • 155
  • 2
    Isn't this all just "angels dancing on the head of a pin"? If a programmer believes "`$a=('foo','bar')` is evaluation of a list in scalar context, which evaluates to the right-most element, etc.", what are the consequences? How will this mistaken belief come back to haunt him (aside from getting in a flame war with brian d foy)? With every other common "misconception" about Perl I can think of, there is some simple snippet of code -- empirical evidence -- to prove a point one way or another. Is there any such experiment for this question? Even one looking at internals or opcodes? – mob Nov 22 '11 at 21:27
  • 6
    @mob => if someone thinks that it is a list in scalar context, they might think that with `@a` defined as `qw(a b c)` then in the list literal `(11, 22, @a)` in scalar context, the list expands its arguments, so it becomes `(11, 22, 'a', 'b', 'c')` and then it returns the last argument, `c`. This is of course wrong, and it returns `3` which is `@a` in scalar context. – Eric Strom Nov 22 '11 at 22:09
  • 1
    a code snippet could be: `perl -E '@a = qw(a b c); sub list {@_[0..$#_]} $x = (11, @a); $y = list (11, @a); say "$x, $y"'` which prints `3, c` – Eric Strom Nov 22 '11 at 22:10
  • Thank you, Eric. That clears things up for me (mostly). – mob Nov 22 '11 at 22:16
  • @Eric Strom, A list never expands its operands. An operator's operands are necessarily evaluated before the operator itself, so they are already "expanded" before the list sees them. A list in list context is actually a no-op, so it's usually optimised away. For example, `perl -MO=Concise,-exec -e"my @s = (@x, @y, @z);"` – ikegami Nov 22 '11 at 23:44
  • @mob, What I told Zaid was all about avoid "angels dancing on the head of a pin", actually. People who incorrectly say "there's no such thing as a list in scalar context" have cause a lot of confusion in many people, then we end up having to deal with crazy misconceptions here and on PerlMonks. This started when I told Zaid he shouldn't say that. I suggested he say "A list can't be returned in scalar context" instead, as it avoids the whole angel-pinhead issue. – ikegami Nov 22 '11 at 23:55
  • 2
    @ikegami => Please stop being so incredibly pedantic, it really does not help the conversation. In my comment I was clearly explaining an ERROR THAT A NOVICE MIGHT ENCOUNTER. Say perhaps after reading this in perldata: `LISTs do automatic interpolation of sublists. That is, when a LIST is evaluated, each element of the list is evaluated in list context, and the resulting list value is interpolated into LIST just as if each individual element were a member of LIST. Thus arrays and hashes lose their identity in a LIST`... – Eric Strom Nov 23 '11 at 01:19
  • @Eric Strom, The way I understood what you wrote, it seems you were saying it's normal to think that scalar context lists are expanded because list context lists are expanded. Expressing my disagreement with that is not being pedantic. I've been using "Nit:" when being pendantic. I was being pendantic, I would have said "Nit: s/results in it returning the last item of the list literal/results in it returning the result of the last operand of the list operator/" – ikegami Nov 23 '11 at 01:46
  • 2
    @ikegami => Of course it is wrong, that is the whole point. What if someone did not understand how context propagates, and read that in perldata? Then they might come to the conclusion expressed in my answer to *mob* who asked for an example misconception. It seems at least 4 other people at the time of writing this understood that. I guess you were not one of them? Was the `This is of course wrong` and the following code example somehow not clear enough to you? (the irony of discussing how you seem to have missed the propagation of context in this comment chain is not lost on me...) – Eric Strom Nov 23 '11 at 02:17

6 Answers6

8

A list literal is something that is actually a list written out in code, so (1, 2, 3) is a list literal, whereas caller for example is a function that could return a list or a scalar depending on context.

In a line like:

my $x = ...;

the ... sees scalar context, so if ... was a list literal, then you would have a list literal in scalar context:

my $x = (1, 2, 3);

but the list literal does not result in a list, because the comma operator it contains sees scalar context, which then results in it returning the last item of the list literal, and throwing the remaining values away after evaluating them.

In terms of a function, the function itself sees whatever context it is called from, which then is propagated to any line in that function that returns. So you can have a function in scalar, list, or void context, and if the last line of that sub happens to be a list literal, that list literal will see any of those contexts and will behave appropriately.

So basically this is a terminology distinction, with list literal referring to a comma separated list of values in the actual source code*, and list referring to a sequence of values placed onto perl's stack.

You can write subroutines with return values that either behave like arrays or like list literals with regard to context.

sub returns_like_array  {my @x = 1..5; return @x}

sub returns_like_list   {my @x = 1..5; return @x[0 .. $#x]}

*or something that results in a list of comma separated values, like a qw() or a fat comma => or a hash or array slice.

You can also look at my answer here: How do I get the first item from a function that returns an array in Perl? which goes into a bit more detail about lists.

Community
  • 1
  • 1
Eric Strom
  • 39,821
  • 2
  • 80
  • 152
  • I'm torn between accepting your answer and ikegami's. Both have given me better understanding about this point. Thanks! – Zaid Nov 23 '11 at 02:51
3

I agree with you and with perlfaq4. To quote perldata, which is probably the definitive documentation on this point:

In a context not requiring a list value, the value of what appears to be a list literal is simply the value of the final element, as with the C comma operator.

(emphasis mine).

That said, ikegami is entitled to use whatever terminology (s)he wants. Different people think of different language constructs in different terms, and as long as the end results are the same, I don't think it matters if their terminology differs from that in the documentation. (It's not a great idea to insist on idiosyncratic terminology in a public forum, though!)

ruakh
  • 175,680
  • 26
  • 273
  • 307
  • The list operator and the comma operator are two names for the same operator, so perlfaq4 is actually not being truthful. – ikegami Nov 22 '11 at 23:06
  • I don't use that terminology, but it is very commonly used, and it's what Perl uses. (See my answer.) – ikegami Nov 22 '11 at 23:08
  • Finally, It's Zaid that's insisting on idiosyncratic terminology ("no such thing as a list in scalar context"). I simply pointed out what he shouldn't be using (because it's confusing and/or wrong), not what he should be using (so I didn't use any terminology at all). – ikegami Nov 22 '11 at 23:13
3

Just ask Perl!

>perl -MO=Concise,-exec -e"my $s = ($x, $y, $z);"
1  <0> enter
2  <;> nextstate(main 1 -e:1) v:{
3  <0> pushmark v
4  <#> gvsv[*x] s
5  <#> gvsv[*y] s
6  <#> gvsv[*z] s
7  <@> list sKP                      <--- list in (s)calar context.
8  <0> padsv[$s:1,2] sRM*/LVINTRO
9  <2> sassign vKS/2
a  <@> leave[1 ref] vKP/REFC

So yes, one can have a list in scalar context.

One cannot return a list in scalar context. (Well, it is possible from XS, but the program will crash, probably with a "Bizarre copy" error.)


It can't be any other way. If there was a distinct list op and comma op, it would be impossible to compile the following:

sub f { "a", "b", "c" }

Would that result in a list op or a comma op? In reality, there is no such distinction, so yes, it results in that op.

ikegami
  • 367,544
  • 15
  • 269
  • 518
2

It's not a list. Since you're assigning to a scalar, it's the comma operator - evaluates the left side, evaluates the right side, returns the right side, and resolves left-to-right. $scalar will be 'confused' :)

Ry-
  • 218,210
  • 55
  • 464
  • 476
  • @Zaid: ikegami says "Formally, it's a list Perl expression that returns a two element list or a scalar depending on context." – Ry- Nov 22 '11 at 20:07
  • Which implies that there is such a thing as a list in scalar context, which contradicts your answer. – Zaid Nov 22 '11 at 20:09
  • 1
    @Zaid: No, it doesn't imply that at all. – Ry- Nov 22 '11 at 20:09
  • Perhaps I'm missing something here. Care to explain? – Zaid Nov 22 '11 at 20:13
  • @Zaid: It's a list Perl expression that returns a [two element] list or a scalar, depending on context. So if the context is "assigning to a scalar," it will be a scalar. If it's a list context, it'll be a list. – Ry- Nov 22 '11 at 20:17
  • 1
    "List operator" and "comma operator" are two names for the same operator. Contrary to what you said, it's not a binary op, not even in scalar context. (See my answer.) – ikegami Nov 22 '11 at 23:21
  • @ikegami: Well, that's what I get for posting an answer on Perl :P Since you answered, though, well that's the best answer. – Ry- Nov 23 '11 at 01:35
  • @minitech, Your answer isn't bad. In fact, it's what the Perl docs say in one spot. I commented to point out that the docs are at best misleading at times regarding this. – ikegami Nov 23 '11 at 01:57
2

It's a matter of terminology and perspective. Terminology is tricky here because you can write a list in source code, return a list of values, or evaluate something in list context.. and the word "list" means something subtly different in each case!

Technically, a list cannot exist in scalar context because perl (the interpreter) does not create a list of values for things like this:

my $x = ('a', 'b', 'c');

When being pedantic precise this is explained as the behavior of the comma operator in scalar context. Similarly, qw is defined as returning the last element in scalar context so there's no list here, either:

my $x = qw(a b c);

In both of these cases (and for any other operator examples that we could muster up) what we're saying is that the interpreter doesn't create a list of values. That's an implementation detail. There's no reason that perl couldn't create a list of values and throw away all but the last one; it just chooses not to.

Perl the language is abstract. At a source code level ('a', 'b', 'c') is a list. You can use that list in an expression that imposes scalar context on it, so from that perspective a list can exist in scalar context.

In the end, it's a choice between mental models of how [Pp]erl operates. The "A list in scalar context returns its last value" model is slightly inaccurate but easier to grok. As far as I know there aren't any corner cases where it is functionally incorrect. The "There's no such thing as a list in scalar context" model is more accurate but harder to work with as you need to consider the behavior of every operator in scalar context.

Michael Carman
  • 30,628
  • 10
  • 74
  • 122