Luchian Grigore Luchian Grigore - 1 month ago 6
C++ Question

Does it make sense for unary operators to be associative?

The C++ operator precedence table from http://en.cppreference.com/w/cpp/language/operator_precedence (I know it's not normative, but the standard doesn't talk about precedence or associativity) marks unary operators as right/left associative.

From a discussion on a different question, I'm left with doubts. Does it make sense for unary operators to be associative?

Answer

It's just an artefact of the way that the associativity is derived from the grammar.

The reason that addition is left-associative is that one of the productions for additive-expression is additive-expression + multiplicative-expression, with the additive-expression on the left. So when you see:

a + b + c

this must be equivalent to (a + b) + c, because the only way to match the production is with a + b as the additive-expression and c as the multiplicative-expression. a on its own is an additive-expression, but b + c is not a multiplicative-expression and so a + b + c doesn't match the production if we try to take a as the additive-expression.

If you haven't before, I recommend that you read through the "Expressions" chapter ignoring the semantics: look only at the grammar productions. Then you'll see just how it is that precedence and associativity are defined by the grammar. The big trick is that every "high-precedence" type of expression IS-A "lower-precedence" type of expression. So every multiplicative-expression is an additive-expression, but not vice-versa, and this is what makes multiplication "bind tighter" than addition.

Prefix unary operators are defined in the grammar like: unary-expression: ++ cast-expression and so on, with the operator on the left for prefix and on the right for postfix. In other words, we "insert the parentheses" on the left for postfix and on the right for prefix. That is, we can say that the grouping is left-to-right for postfix operators and right-to-left for prefix operators. And indeed the C++ standard says exactly that (5.2/1 and 5.3/1 in C++03). It might be an abuse of terminology or at least a new coinage to refer to this unary grouping as "associativity". But it's not a major one since it's obvious what must be meant.

The only difference here between binary and unary operators is that the syntax would still make sense if the binary operators grouped in the opposite direction, so a - b - c means a - (b - c). It would be surprising but would not otherwise affect the language. With unary operators it would be more than surprising to group !!a as (!!)a, the language would also have to supply a meaning for the sub-expression !!, which currently it doesn't have. A functional language could give it a meaning: !! might mean the function composed from ! and !, i.e. the same operation as static_cast<bool>(), but C++ has no concept of composing functions or operators. The reason C++ doesn't need to supply that meaning is that ! "groups right-to-left". Which (because of the big trick in the grammar) is just another way of saying that !! is not a syntactically correct expression so is never a sub-expression of anything.

So yes, it does make sense to say that prefix operators group right-to-left and postfix operators group left-to-right. But it's also "obvious" that it must be this way around, because of other things we know about the C++ language.

Btw, I think that technically speaking in C++ at least, postfix ++ is not a unary operator. It's a postfix operator. But that really doesn't matter except that it's the terminology in the standard, because obviously it is an operator and it has one operand, so is "unary" in English.

Comments