The comma operator

Beginners are often startled by the following Perl behavior, and I admit this is one side of Perl that is not really attractive (anymore? or ever?):

$a = 6, 1, 1, 1, 7; say $a; # 6
$a = (6, 1, 1, 1, 7); say $a; # 7
@a = (6, 1, 1, 1, 7); $a = @a; say $a; # 5

Why such seemingly inconsistent and strange behavior?

In the first case:

$a = 6, 1, 1, 1, 7; say $a; # 6

Perl evaluates the above as:

($a = 6), 1, 1, 1, 7; say $a; # 6

since the assignment operator has a higher precedence than the binary comma.

In the second case:

$a = (6, 1, 1, 1, 7); say $a; # 7

It is just the binary comma operator in action. In the scalar context, the comma operator (quoting the perlop manpage verbatim) "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." So the end result is the rightmost argument.

The last case:

@a = (6, 1, 1, 1, 7); $a = @a; say $a; # 5

is just evaluating an array in scalar context. From perldata: "If you evaluate an array in scalar context, it returns the length of the array."

What if we want to find the length of a list without assigning it to an array first? We cannot just do:

$a = (6, 1, 1, 1, 7);

or even:

$a = scalar(6, 1, 1, 1, 7);

since "Note that this [evaluating an array in scalar context] is not true of lists, which return the last value, like the C comma operator, nor of built-in functions, which return whatever they feel like returning". So we need this trick:

$a = () = (6, 1, 1, 1, 7); say $a; # 5

Not exactly intuitive :-)

Further reading: perlop (the binary comma operator), perldata (context), perlsecret.

12 Comments

Rather than using the unintuitive "=()= operator" you can also use the maybe-slightly-more-intuitive-ish-but-probably-slower arrayref-deref option:

$a = @{ [ (6, 1, 1, 1, 7) ] }; say $a; # 5

-------

Although when you would use that over the much more intuitive, optimized, etc...

my $a = 5; say $a; # 5

... I don't know ;-)

$ perl -E'$a = () = (6, 1, 1, 1, 7); say $a;'
5
$ perl -E'@a = () = (6, 1, 1, 1, 7); say @a;'

$

Why? In the first one, the array is kept. In the second, it is fitted first to `()` which throws everything away, then assigned to `@a` so that it's an empty array. This seems inconsistent to me.

What array is kept? There is no array in either of your code examples. In the first one, you place a list assignment in scalar context, which evaluates to the number of elements on the right-hand side. In the second one, the list assignment is in list context, where it evaluates to the left-hand side. That is not consistent but just seems fine to me: it is more useful like this than if it were consistent either one way or the other.

“In general”, to quote Larry about Perl’s operators, “they do what you want, unless you want consistency.”

consistency = predictability

inconsistency = gotchas

Maybe Perl wasn’t the best choice then. :-)

shawnhcorey:
consistency = predictability
inconsistency = gotchas

Aristotle:
Maybe Perl wasn’t the best choice then. :-)
-------------------------------------------

Maybe this is why we have a hard time bringing new blood into Perl.

Maybe this is why we have a hard time bringing new blood into Perl.

Because @x = () = (1,2,3) and $x = () = (1,2,3) are, strictly speaking, inconsistent?

I see…

The most regular and consistent languages I can think of off hand are Lisp and Smalltalk, btw… *chin scratch*

Well if someone really values consistency very highly, there is no way of selling them Perl and no point in trying. The design of the language does in fact – though it tries to avoid breaking consistency for no good reason – not treat it as a primary goal. If that is what you want in a programming language, well, then you won’t be very happy with Perl and why should I try to convince you that your misery is enjoyable?

OTOH, frankly, I don’t think Shawn’s position is very deeply reflected, which I was implying in the last comment. All languages have inconsistencies, and generally the popular ones strike a balance between convenience of various kinds and consistency of various kinds. (That choice is not necessarily conscious – just inevitable.) If consistency was that important, then nobody would be using PHP – yet it ate Perl’s big niche, in spite of being much worse in that (and many another) respect. (Oh so many others… so, so many.)

We can reasonably have a discussion about whether Perl draws the line too far in one direction or the other, and about whether any particular instance is out of balance with the rest of Perl. (I think it tries and very largely succeeds to strike a balance that few other languages attempt. That is what I can say to sell it!) But that requires cognizance of the fact that there is a spectrum and the extremes are rather sparsely populated – not just a binary.

And even then, again, if someone does value consistency much more highly than it is valued in the design of Perl, there is not much that can – or should! – be done to sell them on Perl. I’ve tried to work with Python, and I've tried to use Emacs. Both grate on me, they cut against my mental grain (in general ways with lots of very particular implications). Trying to sell them to me would be useless – I wouldn’t be won over, no matter what. (I’m fine using them if necessary, mind you: they are fine products and I can see their appeal. I just have peculiarities they are optimised against.) I’m keenly aware that likewise Perl and vi cut against other people’s mental grain.

That’s OK! I’m not of the opinion that every other language, editor, etc. has to lose in order for the ones I prefer to “win”.

I guess “maybe Perl wasn’t the best choice then” was also an invitation to reflect – admittedly, perhaps an overly coy one. “Will you be happy here then? And if you aren’t unhappy, how do you value consistency – truly?”

Can you please cover this case:

@list = 2, 3, 4;
print @list; # 2;

Leave a comment

About Steven Haryanto

user-pic A programmer (mostly Perl 5 nowadays). My CPAN ID: SHARYANTO. I'm sedusedan on perlmonks. My twitter is stevenharyanto (but I don't tweet much). Follow me on github: sharyanto.