Reputation: 141
QUESTION IS: If this issue is clear to you, please explain to me what im not seeing. My question is: How does ternary actually work? To clarify my question: What does right to left associativity really mean here? Why is associativity not the same as order of evaluation? It is clearly like an if else statement. It is not evaluated from right to left. It seems to me to be left to right associative.
I made booleans to try and prove this. It shows me it isnt right associative.(I might not understand what right associative means.) If it was right associative, it would work like this, which was an answer which was given to me:
"Since this operator is right-associative, your code works as;"
true ? false ? false ? false ? 3 : 4 : 5 : 6 : 7
evaluated as;
true ? false ? false ? (false ? 3 : 4) : 5 : 6 : 7
which evaluated as;
true ? false ? false ? 4 : 5 : 6 : 7
which evaluated as;
true ? false ? (false ? 4 : 5) : 6 : 7
which evaluated as;
true ? false ? 5 : 6 : 7
which evaluated as;
true ? (false ? 5 : 6) : 7
which evaluated as;
true ? 6 : 7
which returns 6.
I tried to prove this, like this:
int Proof = ternaryTrueOne() ? ternaryTrueTwo() ? ternaryFalseOne() ?
ternaryTrueThree() ? ternaryFalseTwo() ? 2 : 3 : 4 : 5 : 6 : 7;
static bool ternaryTrueOne()
{
Console.WriteLine("This is ternaryTrueOne");
return true;
}
static bool ternaryTrueTwo()
{
Console.WriteLine("This is ternaryTrueTwo");
return true;
}
static bool ternaryTrueThree()
{
Console.WriteLine("This is ternaryTrueThree");
return true;
}
static bool ternaryFalseOne()
{
Console.WriteLine("This is ternaryFalse");
return false;
}
static bool ternaryFalseTwo()
{
Console.WriteLine("This is ternaryFalseTwo");
return false;
}
In that case this would be evaluated in the same way. Right? That means ternaryfalsetwo would write first in to the console. But it doesnt. It doesnt write at all. It actually works like this, and ive written the ternary expression as an if statement. It works left to right, and it does not have to evaluate the rest of the code. All other statements are unreachable after the first false statement.
private static int Proof2()
{
if (ternaryTrueOne())
{
if (ternaryTrueTwo())
{
if (ternaryFalseOne())
{
if (ternaryTrueThree())
{
if (ternaryFalseTwo())
{
return 6;
}
else
{
return 7;
}
return 5;
}
else
{
return 6;
}
return 4;
}
else
{
return 5;
}
return 3;
}
else
{
return 4;
}
return 2;
}
else
{
return 3;
}
}
Was the original answer wrong? What does right associativity really mean?
Upvotes: 5
Views: 864
Reputation: 234715
Since the ternary conditional operator has its own place in the operator precedence table, (i.e. no other operator has exactly the same precedence as it), the associativity rule only applies when disambiguating a conditional operator from another.
Right to left associativity means that the implicit parentheses are around the rightmost ternary.
That is,
a ? b : c ? d : e
is equivalent to
a ? b : (c ? d : e)
.
https://en.wikipedia.org/wiki/Operator_associativity is a useful link.
Upvotes: 5
Reputation: 63742
Associativity and order of execution are related, but not identical.
Associativity exists regardless of any execution - it's defined in math, which is exclusively formed of pure functions, so "order of execution" has no bearing on the result.
The order of execution in a ternary operator in C# is very simple:
You can imagine associativity rules as "where do the parens belong".
Consider this:
a ? b : c ? d : e
If we don't know anything about how associativity works, we can see different ways of putting the parens:
The first approach is left-associative, the second is right-associative
It shouldn't be hard to see that the two approaches lead to different results. For example,
(true ? true : false) ? false : false // false
true ? true : (false ? false : false) // true
Now, if you rewrite this in separate if
statements (which usually isn't the way a ternary is actually executed, but it will do), you'll get this:
if (a)
{
return b;
}
else
{
if (c) return d;
else return e;
}
The evaluation is the same as with the simple ternary:
a
b
; otherwise continuec
d
; otherwise evaluate and return e
This should make it obvious how associativity and order of execution works. So we can finish the trip, and explain your example.
We have a series of nested conditionals:
a ? b ? c ? 0 : 1 : 2 : 3
How does associativity apply here? It doesn't. There's no associative operation here! What you're doing is:
a ? (b ? (c ? 0 : 1) : 2) : 3
There's no other way to put the parens - this is the only possible way of parsing the operators.
Since the ternary operator is, well, ternary, this is a bit hard to see, but it becomes more obvious when you rewrite it as a function (e.g. "non-inline operator"):
var f = (a, b, c) => a ? b : c;
f(a, f(b, f(c, 0, 1), 2), 3);
There's no ambiguity - there's no alternative way to parse this expression.
Showing associativity with binary operators is a bit simpler, so consider this scenario:
a - b - c
If you don't know about the associativity of -
, you can see two alternative ways of putting the parens - (a - b) - c
and a - (b - c)
, which can give you two different results. Thus, -
is not associative.
Compare to +
, which is ("fully") associative - (a + b) + c
and a + (b + c)
are exactly the same thing.
Upvotes: 4