dsb has asked for the wisdom of the Perl Monks concerning the following question:

Yes, another issue with a strange and underestimated operator. Here I thought commas were good for only seperating list elements. Well, I guess in a sense I was right...but I didn't realise how much of an effect the low precedence of the comma operator would have on the outcome of a program. I tried a bunch of different things with assignment operators and print statements to see if I could get the gist of the way the comma operator will behave in different situations.
This all started when I first started using the comma operator in print statements like this:
```\$foo = "bar";
print \$foo, "\n";
At first I didn't know what was going on there, but then I realized that expression was being evaluated as:
```print(\$foo,"\n");
That's when I decided to play around a bit to see just what kind of chaos I could cause with the comma operator and different combos of parentheses.

```(\$a,\$b,\$c) = (1,2,3);    # started off easy
# does the expected
Everything is in list context here. \$a is assigned 1, \$b is assigned 2, \$c is assigned 3.
```\$a,\$b,\$c = (1,2,3);      # left side acts weird
The left side of the = uses the last valid option, \$c(as if being evaluated in scalar context) and then the right side is evaluated in scalar context returning the last valid option, 3. So \$c is assigned 3, \$a,\$b are both undefined.

The next one was a puzzler:

```\$a,\$b,\$c = 1,2,3;
The right side acts the same as in the last example. The left side though, acts kinda strange. With out the parentheses, the left side is no longer a list, so only 1 is evaluated, so \$c is assigned 1. I would've though the left side would still evaluated as a list in scalar context returning 3. I'm not really sure why it didn't.

Things got kinda funky when I started messing with print statements.

```print(1),print(2),print("\n");

# output
# 12          - followed by newlin
I thought that was strange since in that statement the comma is acting almost as a line terminator. That one acts as if it was coded:
```print 1;
print 2;
print "\n";
perlfunc pretty much says "If it looks like a function, it is a function". So, when print is called with its argument in parentheses, it is treated like a function call. Fine. What I thought was weird was that this pseudo-list was entirely executed. That is, I didn't think the print(2) and print("\n") would execute. Remembering how fishy things got last time I removed parentheses, I tried this:
```print 1, print 2, print "\n";

# output
[blankline]
2111
Interesting. Best as I can figure, that one evaluated to print(1, (print 2,(print "\n")));. So it executes from inside to outside(sort of like simlyfying a math expression). The newline is printed first, then second-innermost print is execute with its 2 arguments,2, and the return value of print "\n" which is 1(or true. Those two values are printed. Then the print outside all parentheses is called with 1 as its first argument and the return value of print 2,(print "\n")(which evaluates to 1) as its second.

The funny part is, I understand why that one worked out the way it did. I don't understand why:

```print(1),print(2),print("\n");
executes like 3 seperate statements. I'm guessing the comma saves the program from a syntax error, but why does it allow the other list items to execute.

Anyway, that's it. I don't know why that damn thing acts like it does sometimes(specifically the examples I gave), so if anyone can shed any light on things that would be good.

Thanks.

Amel - f.k.a. - kel

Replies are listed 'Best First'.
Re: The Comma Operator
by japhy (Canon) on Jul 20, 2001 at 03:21 UTC
The comma operator is twofold; in scalar context, it evaluates the left argument, then the right argument, and returns the right argument.
```\$x = (1 + 3, 5 + 7);  # \$x gets 12
\$y = (pop @r, 1000);  # @r gets pop()ed, \$y gets 1000
It has less precedence than =, so:
```\$a, \$b = 1, 2;
means
```\$a, (\$b = 1), 2;
In any other context, it just separates two expressions.
```foo(), bar(), blat() if bonk();

@a = (1,1,2,3,5,8,13);

_____________________________________________________
Jeff japhy Pinyan: Perl, regex, and perl hacker.
s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

Re: The Comma Operator
by lestrrat (Deacon) on Jul 20, 2001 at 03:05 UTC

With my limited knowledge on this, I think this is what's happening: First of all the comma operator in scalar context evaluates the left side, throws it away, and then return the right side. ie.

```   \$a, \$b, \$c = 1, 2, 3;

the order of evaluation is
(((( \$a ), \$b ), \$c = 1 ), 2), 3)

so...
1) \$a gets evaluated
2) \$b gets evaluated
3) \$c = 1 gets evaluated
4) 2 gets evaluated
5) 3 gets evaluated
6) return 3

Same thing for print:

```    print( 1 ), print(2), print("\n" );

1) print (1 ) gets evaluated
2) print ( 2 ) gets evaluated
3) print ( "\n" ) gets evaluated
4) return result of print ("\n")

P.S. -- I'm taking an educated guess here, so feel free to correct me if I'm wrong... :-)

Re: The Comma Operator
by petral (Curate) on Jul 20, 2001 at 11:48 UTC
I once worked out this convoluted way to access time only once per reading without using a temporary.
```perl -lwe'\$oldtime = \$^T;

print( -((\$oldtime+0) - (\$oldtime = time)) )
while sleep 1'
(Not to be obscure: the normal way to do this is something like:my \$tm = time;  print \$tm - \$oldtm;  \$oldtm = \$tm; The only complicating factor being that you don't want to call time() twice since it may roll over in between.  In order to avoid using a temporary, the old value of oldtime must be put into the calculation before oldtime is set to its new value which must also be used. A substraction requires that its arguments be ordered, and sub-expressions for both parts seems to work.)

But note well, the docs often note that the order of evaluation of arguments to functions is not defined. (This is a long-time caveat carried over from c.) For instance, the above can easily be broken:( -((\$oldtime || \$^T) - (\$oldtime = time)) ) returns a stream of -0's!

Udpate: And here's a fibonacci series that depends on \$b being returned *before* it is updated.
```perl -e'\$\=\$,=\$";\$b=1;
print \$b, \$a += \$b += \$a while \$a <1000;
print"\n"'
Update the second: Note also, that any halfway ambitious optimizer could reduce -( (x + 0) - (x = y) ) to (x = y) - (x) to x - x to 0 and produce:print 0;
p

Re: The Comma Operator
by da (Friar) on Jul 20, 2001 at 19:24 UTC
This is an excellent application for Deparse. The -p parameter to Deparse gives you nearly as many parenthesis as perl can give you, which is useful for explainging things. I was first exposed to this trick by Brother MeowChow when I asked how in hell his .sig worked.

```> perl -MO=Deparse,-p -e '\$d, \$e, \$f = 1,2,3;'
-e syntax OK
(\$d, \$e, (\$f = 1), '???', '???');
The latter arguments are thrown away because the '=' binds more tightly than the comma. If these were subroutines, they would have evaluated before being discarded.
```> perl -MO=Deparse,-p -e 'print(1),print(2),print("\n");'
-e syntax OK
(print(1), print(2), print("\n"));
Note the parens around everything; to answer your question about why it evaluates all three terms, it is a list that gets discarded after evaluating its elements, which look like functions so they're evaluated as functions.
```> perl -MO=Deparse,-p -e 'print 1, print 2, print "\n";'
-e syntax OK
print(1, print(2, print("\n")));
And your description was exactly right.

```___
-DA
> perl -MPOSIX -le '\$ENV{TZ}="EST";print ctime(1000000000)'
Sat Sep  8 20:46:40 2001
Re: The Comma Operator
by PetaMem (Priest) on Jul 20, 2001 at 19:00 UTC
And - as was pointed out not long ago - donīt use \$a and \$b
(naming your program or module test could do also... :-))

Ciao

Re: The Comma Operator
by kael (Monk) on Jul 21, 2001 at 10:10 UTC
With the comma list of prints your just making a list and ignoring it's acutal value
```@a=(foo,bar,bah);
valid code, right? now how bout this?
```(foo,bar,bah);
```@a=(joe(),someothersub());
```(joe(),someothersub());
```(print("hello"),print "\n");