When does operator associativity matter?
Asked Answered
S

2

5

Most programming languages have a table of precedence and associativity for binary operators. Associativity matters in some cases e.g. (a - b) - c != a - (b - c).

However, for an associative operator like && it would seem not to matter, yet most languages list this as left associative.

Are there any situations where there is actually a difference between (a && b) && c and a && (b && c)?

Salot answered 17/11, 2013 at 10:57 Comment(9)
Think of what happens when a, b and c are functions that have side-effects.Fado
Most languages also implement short circuitingAalii
@Juhana: What happens? As far as I can tell, nothing different.Annaleeannaliese
@Mehrdad, side effects can change the result of the evaluation resulting in different results.Illuse
@kviiri: Example C code please?Annaleeannaliese
@Mehrdad If you have a() && b() then a() is called first if && is left-associative. If it's right-associative then b() is called first. That's why associativeness matters.Fado
@Juhana: Uhm no, evaluation order is not the same thing as associativity or precedence.Annaleeannaliese
It would make no sense to have a different evaluation order than associativity/precedence in this case.Fado
@Juhana: That's an entirely different argument, let's not mix them up. You're right that it's not useful to define them differently for &&... but there's nothing technically wrong with that. My point was only that they don't make a difference in the evaluation order.Annaleeannaliese
A
9

I can't believe there are so many wrong (deleted) answers... maybe I should answer this.

First of all, precedence != associativity != evaluation order.

Now that we have that out of the way: associativity matters in some cases.
For a + b + c, it matters when a, b, and c are floating-point numbers instead of integers, because rounding errors will accumulate differently depending on how the terms are grouped.

For the particular case of && and ||, it doesn't matter as long as they aren't overloaded (which is possible only in C++, not C), but the language still defines one just for consistency -- and so that the "tree" representation of the code (based on the grammar) is unique. That also works out to the benefit of C++ since now the meaning of overloaded && and || isn't ambiguous.

Annaleeannaliese answered 17/11, 2013 at 11:23 Comment(0)
M
1

Adding to @Mehrdads@ answer (which I upvoted):

If you ever constructed a parser, you'll notice that your operators have to have an associativity, otherwise

a && b && c

would be simply a syntax error. Assuming that the above should not be a syntax error, you must decide if it should mean:

(a && b) && c

or

a && (b && c)

You can't just say: I don't care.

Marney answered 17/11, 2013 at 19:16 Comment(8)
Right. Most parsers go with the former. I noticed that it would make the parser slightly simpler if I went with the latter, hence my question, to make sure it wouldn't break anything.Salot
It really depends on the operator, @rwallace. Isn't exponentiation right associative in many languages? In Haskell, also there are many right associative operators. But surely, nobody wants a/b/2 mean 2a/bMarney
Actually in this case you really don't have to care as long the order of operations for && is defined (e.g. always evaluate left operand first). You could start with a && ??? and start by evaluating a without "peeking" at what follows. This is in fact a requirement, otherwise there is an unintended dependency on the RHS of the short-circuit operator. There may be standard techniques for parsing, but even those are largely by convention. A line-by-line interpreter could evaluate such an expression and only continue parsing after evaluating a.Tarango
@CPerkins You could do that, but then you would have implemented right associativity, plain and simple. That we must choose between left and right associativity simply follows from the fact that we're dealing with binary operators here.Marney
@Marney It's just that Mehrdad's answer says "it doesn't matter", then your answer says it is "adding" to Mehrdad's, but then contradicts it by saying "must decide", and that "You can't just say: I don't care. So which is it? Your answer only considers associativity which concerns multiple operators, but the peculiar thing about && is that the individual operator (which has nothing to do with associativity) demands that the left operand is evaluated first.Tarango
So even if one places explicit parenthesis like (a && b) && c to force left associativity (as opposed to my previous comment which you interpret as right associativity), then even if the parser fully tokenizes and groups operands together (associates them), it turns out that a must always be evaluated first, then the operator dictates whether any of the other operands that follow are even evaluated. The fact that && has its own precedence level with no other operator and the nature of it forcing the left operand to evaluate first results in the same behavior no matter if left or right.Tarango
So if the overall result is identical, then it's back to Mehrdad's answer that "it doesn't matter" and so one can say "who cares". Or if it fits your concept of parsing, then the nature of the operators evaluation essentially forces it to have right associativity regardless of the parenthesis or the default standard associativity assigned to it.Tarango
@CPerkins but Mehrdad said "the language still defines one" (an associativity), this was the comment I wanted to elaborate on by pointing out that, no matter what && means, as long as it is a binary operator, you'll have an associativity, like it or not. Mehrdad also said associativity is not the same as execution order, so you're right in saying that different grouping of multiple && does not affect evaluation order.I never disputed this.Marney

© 2022 - 2024 — McMap. All rights reserved.