Java operator precedence guidelines
Asked Answered
W

6

21

Misunderstanding Java operator precedence is a source of frequently asked questions and subtle errors. I was intrigued to learn that even the Java Language Specification says, "It is recommended that code not rely crucially on this specification." JLS §15.7 Preferring clear to clever, are there any useful guidelines in this area?

As noted here, this problem should be studied in the context of Evaluation Order, detailed here. Here are a number of resources on the topic:

Additions or corrections welcome.

Wilkins answered 26/1, 2010 at 5:42 Comment(5)
When in doubt, add more parentheses.Puisne
And when there's too many parentheses, refactor.Wilkins
That JLS quote (in context) encourages decomposition of statements that have multiple side-effects (or side-effects in sub-expressions) to avoid uncertainty about the relative timing of said side-effects in left and right sub-expressions. This cannot be accomplished by adding parentheses. In other words, the JLS advises against relying on Java's Evaluation Order, not against relying on operator precedence. The difference between these is explained below, and here.Tinishatinker
((When)(in)((doubt)(,)(add more)((parentheses)?)) No, thank you. Add the minimal amount, please.Giza
@KevinPanko: For example.Wilkins
D
20

As far as the "Real World" is concerned, it's probably fair to say:

  • enough programmers know that multiplication/division take precedence over addition/subtraction, as is mathematically the convention
  • hardly any programmers can remember any of the other rules of precedence

So, apart from the specific case of */ vs +-, I'd really just use brackets to explicitly define the precedence intended.

Decisive answered 26/1, 2010 at 5:42 Comment(14)
Did you mean brackets or parenthesis'?Aubyn
The reason programmers hardly can remember is because each language is slightly different.Inhuman
They are slightly different in different languages, but even programmers of a single language generally don't memorise the list. @Anthony -- in my world, parentheses are a type of bracket.Decisive
I was just thinking in terms of operators precedence, I thought it was parentheses that determined precedence. I just wasn't sure if you meant the { block when referring to bracketsAubyn
@Neil: All oarentheses may be brackets, but not all brackets are parentheses.Pico
You can also rely on relational operators (<, <=, ==, >=', >') having precedence over logical operators (&&, ||.)Illuminism
@Neil - when talking to IT folks, it is best to stick to conventional IT / typographic terminology. '()' are parentheses (or round brackets), '[]' are brackets (or square brackets) and '{}' are braces (or curly brackets).Rhoades
Stephen -- could this be a US thing by any chance? In UK English, even among programmers, it's really OK to call () "brackets". If you say "brackets", I really don't think anyone will think you mean [] unless you specify "square" brackets. Really!!Decisive
In the context of operator precedence, "brackets" can really only mean "round brackets".Helminthic
"hardly any programmers can remember any of the other rules of precedence". So true.Alidaalidade
Hopefully most programmers at least remember "Please Excuse My Dear Aunt Sally" from middle school.Compendious
Well, I would really expect most programmers to instantly know the order of precedence of the very basic operators without resort to a silly middle school mnemonic. In all honestly, if that learning curve is too high for somebody, I would probably suggest a different career path.Decisive
@Compendious that must be an americanism, in the uk we have BIDMAS :)Angelika
Vaguely recall our maths teacher using "BODMAS". Either way, for those of an anal disposition, the "B" evidently stands for "parentheses"...Decisive
G
5

Another related source of bugs is how rounding errors accumulate. Not an operator precedence order issue per se, but a source of surprise when you get a different result after rearranging operands in an arithmetically-equivalent way. Here's a sun.com version of David Goldberg's What Every Computer Scientist Should Know About Floating-Point Arithmetic.

Ghostwrite answered 26/1, 2010 at 5:42 Comment(0)
T
4

The quote (from the Java Language Specification §15.7) should be read in the context of Evaluation Order. As discussed here, that section concerns evaluation order, which is not related to operator precedence (or associativity).

Precedence and associativity influence the structure of the expression tree (i.e. which operators act on which operands), while "evaluation order" merely influences the order in which the expression tree is traversed when the expression is evaluated. Evaluation order (or "traversal order") does not have any effect unless some sub-expressions have side-effects that affect the result (or side-effects) of other sub-expressions.

For example, if x==1 initially, the expression ++x/++x would evaluate as 2/3 (which evaluates to 0) since Java has left-to-right evaluation order. Had evaluation order in Java been right-to-left, x would have been incremented twice before the numerator is evaluated, and the expression would have evaluated as 3/2 (which evaluates to 1). Had evaluation order been undefined, the expression could have evaluated to either of these results.

The quote in question, together with its context, ...

The Java programming language guarantees that the operands of operators appear to be evaluated in a specific evaluation order, namely, from left to right.

It is recommended that code not rely crucially on this specification. Code is usually clearer when each expression contains at most one side effect, as its outermost operation

...discourages the reader from depending on the left-to-rightness of Java's evaluation order (as in the example above). It does not encourage unnecessary parentheses.

Edit: Resource: Java operator precedence table that also serves as an index into sections of the JLS containing the syntactic grammar from which each precedence level is inferred.

Tinishatinker answered 26/1, 2010 at 5:42 Comment(5)
Evaluation order refers to the order in which sub expressions are evaluated, for example (a+b)/(c+d). It is guaranteed to be left before right. It doesn't affect how the / operator itself is evaluated in the slightest. Your example about 2/3 as against 3/2 is completely incorrect. It has nothing to do with tree traversal either: it is a property of the generated code, where there is no expression tree at all, just RPN.Goeger
@EJP Well RPN is just a way of encoding an expression tree, and processing RPN sequentially amounts to exactly the traversal that I was referring to. As for your assertion that my example is "completely incorrect", are you in fact claiming that ++x/++x would evaluate to the same result under LTR and RTL evaluation order?Tinishatinker
Thank you for this helpful colloquy. I intended to focus on how the "language respects the order of evaluation indicated explicitly by parentheses and implicitly by operator precedence," but I see that both (parentheses and precedence) must be taken in the overall context of Evaluation Order. Isak: I see no such claim by EJP. EJP: I inferred that Isak was writing hypothetically.Wilkins
Well +1 for diplomacy @trashgod. People have different opinions on the answer to your question. I just thought it could be useful to point out that the JLS doesn't offer the opinion you thought it does, in that quote.Tinishatinker
@EJP has guided me more than once, so I generally assume ignorance on my part, rather than error on his. I've edited my question to include the link you cited and revised your answer to emphasize the larger context. You might replace your comment on the question with one citing this answer.Wilkins
D
2

The JLS does not give an explicit operator precedence table; it is implied when the JLS describes various operators. For example, the grammar for ShiftExpression is this:

ShiftExpression:
    AdditiveExpression
    ShiftExpression << AdditiveExpression
    ShiftExpression >> AdditiveExpression
    ShiftExpression >>> AdditiveExpression

This means that additive operators (+ and -) have a higher precedence than the left-associative shift operators (<<, >> and >>>).

Drool answered 26/1, 2010 at 5:42 Comment(0)
C
2

Also, don't forget the logical && and || are shortcut operators, avoid something like:

sideeffect1() || sideeffect2()

If sideeffect1() is evaluating to true, sideeffect2() isn't going to be executed. The same goes for && and false. This is not entirely related to precendence, but in these extreme cases the assiociativity can also be an important aspect that normally is really irrelevant (at least as far as i am concerned)

Clupeid answered 26/1, 2010 at 5:42 Comment(1)
In Java, the & and | operators can be boolean logical (as well as bitwise integer). These are the non-short-circuiting operators. Using || instead of | is an explicit request for conditional operand evaluation, much like ?:.Tinishatinker
Z
1

It seems to me that the truth of this is that 'most programmers' think 'most other programmers' don't know or can't remember operator precedence, so they indulge in what is indulgently called 'defensive programming' by 'inserting the missing parentheses', just to 'clarify' that. Whether remembering this third-grade stuff is a real problem is another question. It just as arguable that all this is a complete waste of time and if anything makes things worse. My own view is that redundant syntax is to be avoided wherever possible, and that computer programmers should know the language they are programming in, and also perhaps raise their expectations of their colleagues.

Zolnay answered 26/1, 2010 at 5:42 Comment(2)
Sorry, to me this is argumentative. I agree more with the JLS 15.7. Will they ever change the order? Who knows. But I can tell you that I've worked on projects with both C++ and Java code, which have subtle differences in precedence (e.g.: defined vs undefined precedence), and most of our developers would rather be sure of the order of evaluation when they might be coding Java one day and C++ the next.Towner
@OgrePsalm33 (a) Of course it's 'argumentative': if you mean 'debatable', the question invited a debate; (b) JLS 15.7 isn't about operator precedence, it is about evaluation order; (c) no, they will never change the operator precedence; (d) there is no undefined operator precedence in either Java or C++, or any other language I am aware of: it is impossible to construct a parser with an undefined grammar; (e) parentheses do not control evaluation order.Goeger

© 2022 - 2024 — McMap. All rights reserved.