Thread overview
What is a "comma expression"?
Oct 10, 2021
rempas
Oct 10, 2021
Elmar
Oct 10, 2021
rempas
Oct 10, 2021
Adam D Ruppe
Oct 10, 2021
rempas
October 10, 2021

This is the first time I'm finding something like that. I'm having the following code in C:

  if (0 == (i >> 7)) {
    if (len < 1) return -1;
    v = i;
    return *ret = v, 1;
  }

This is part of a function that returns an int. When I'm running this in C, it works. However in D, I'm getting the following error message:

Error: Using the result of a comma expression is not allowed

Can someone explain what comma expressions are and why they don't work in D (or if the only doesn't work as returned values from a function)?

October 10, 2021

On Sunday, 10 October 2021 at 12:01:33 UTC, rempas wrote:

>

This is the first time I'm finding something like that. I'm having the following code in C:

  if (0 == (i >> 7)) {
    if (len < 1) return -1;
    v = i;
    return *ret = v, 1;
  }

This is part of a function that returns an int. When I'm running this in C, it works. However in D, I'm getting the following error message:

Error: Using the result of a comma expression is not allowed

Can someone explain what comma expressions are and why they don't work in D (or if the only doesn't work as returned values from a function)?

Hello rempas.

The comma-operator , is like ; but results in an expression value, not a statement like ; would. The left side of , is executed like a statement and the value of the right side of , is returned. Comma-expressions are merely used to pack additional instructions into places where only expressions are allowed.

if (x = y, myNiceFunction(), yay(x), x > 5)
{
   // ...
}

or

if (hasFancyFunkyStuff)
    x = z, fancy(x), funkyUpdate(z);   // too lazy for braces

Many consider the , operator to be a design-flaw because it makes expressions difficult to read and can be easily abused because the above should actually be:

x = y;
myNiceFunction();
yay(x);
if (x > 5)
{
    // ...
}

In D you can still write the second example of code but not the first example of code. The designers of D thought they could make it less painful by just forbidding comma-expressions to be used as expression value and only as statement. This is because then comma-expressions can still be used in for-loops:

for (x = y, z = a; x < z; x++, z--)
{
    ;
}

In conclusion, your C snippet should actually look like:

  if (0 == (i >> 7))
  {
    if (len < 1)
      return -1;
    *ret = v = i;
    return 1;
  }

The previous snippet even could mislead readers to think that it would return a tuple of two elements which it doesn't.

October 10, 2021
On Sunday, 10 October 2021 at 12:01:33 UTC, rempas wrote:
>     return *ret = v, 1;

The comma expression in C is a combination of two things but in the context of another thing. Well that's not very good, but like there's statements and expressions. Statements do something but do not have a value. So `if() {}` and `return` and `for() {}` are statements, because they don't have a value you can assign to a variable.

Expressions do something but DO have a value and thus you can assign it to a variable.

a = if (true) { a } ; // not permitted because if is a statement

a = 5 + 4; // OK, 5+4 is an expression and thus has a value


This is a slight simplification but generally true. You'll notice in some languages the if assign does work; in those languages you have an if expression rather than an if statement.

The language grammar has rules for where statements are allowed and where expressions are allowed and you can't mix and match (unless the grammar has two rules, one allowing each type).


Anyway, the C comma expression is a combination of two other expressions where the first one is evaluated, but its value discarded, then the second part becomes the value of the whole expression.

a = 1, 2; // the 1 is discarded, so a == 2


It is actually the same as writing out:

1; // evaluate this then discard it
a = 2; // eval this and actually keep the value


The difference being that it is allowed in an expression context.


So that `return *ret = v, 1;`

Could just be written

*ret = v; // this is eval'ed and value discarded
return 1; // second part value is kept


And idk why they didn't just do that here. But the C thing is most commonly seen in a for loop:

for(a = 0, b = 0; a < 5; a++, b++) {}


because the grammar only allows an expression in each piece of the for loop, so you can't separate the two steps by semicolons like you do in different contexts.

> Can someone explain what comma expressions are and why they don't work in D (or if the only doesn't work as returned values from a function)?

D considers it a bit obscure and special-case to use the comma for. There was talk a while ago about making the comma do something else instead, but this never materialized.

But you can always write it out longer form, perhaps wrapping it in a function.

// what I would do here:
*ret = v;
return 1;

// or if you absolutely had to have it in an expression context:

return (){ *ret = v; return 1; }();


The nested function there explicitly does what the comma operator does and is allowed in expression context as well.
October 10, 2021

On Sunday, 10 October 2021 at 12:13:47 UTC, Elmar wrote:

>

Hello rempas.

The comma-operator , is like ; but results in an expression value, not a statement like ; would. The left side of , is executed like a statement and the value of the right side of , is returned. Comma-expressions are merely used to pack additional instructions into places where only expressions are allowed.

[...]

Thanks, that's the second time you are helping me today!

October 10, 2021

On Sunday, 10 October 2021 at 12:19:39 UTC, Adam D Ruppe wrote:

>

On Sunday, 10 October 2021 at 12:01:33 UTC, rempas wrote:

>
[...]

The comma expression in C is a combination of two things but in the context of another thing. Well that's not very good, but like there's statements and expressions. Statements do something but do not have a value. So if() {} and return and for() {} are statements, because they don't have a value you can assign to a variable.

[...]

Thanks a lot for the detailed explanation! Have a nice day!