highest precedence: parenthesis/function/type calls/ternary operator subscripts/slices unary- unary+ not * / + - & < > <= >= = != and or xor lowest precedence: { , , , }Thus 2+6*3 means 2+(6*3) rather than (2+6)*3. Operators on the same line have equal precedence and are evaluated left to right.
The equals symbol ('=') used in an assignment statement is not an operator, but just part of the syntax of the language.
Parenthesis is required to mix
and
, or
, and xor
in an expression. If, for example, the compiler
finds a or b and c
it will
not
assume "(a or b) and c"
over "a or (b and c)"
(or vice versa) but demands you state exactly which you mean. Most programmers have at one point or another coded something
apparently "obvious" such as
if a and b or c and d thenor
if a or b and c or d thenand then been surprised when (some other) compiler gets it completely wrong, unless they actually meant
"(((a and b) or c) and d)"
, or
"(((a or b) and c) or d)"
, which is what most other compilers will assume.
[Python manages quite well on the first, and is probably correct in assuming "(a and b) or (c and d)"
,
but (afaik) it will assume "a or (b and c) or d"
for the second case, irrespective of any indentation.]
To avoid this issue, phix simply forces the programmer to supply enough additional explicit parenthesis until everything is completely unambiguous, eg/ie
if (a and b) or (c and d) thenor
if (a or b) and (c or d) thenThe higher precedence of not usually means that
not a or not b
and (not a) or (not b)
are equivalent, making the extra parenthesis strictly
unnecessary, however I consider it good practice, since it avoids any "oh wait.. is that not (a or not b)
or (not a) or (not b)
?" moments.
On a related note,
"a*(b/c)"
and "(a*b)/c"
are mathematically equivalent, however precision limits of the physical hardware may mean they give
very different results, especially for partial results that approach or exceed the floating point hardware limits.
In practice the compiler treats "a*b/c"
as "(a*b)/c"
, however in general that is an implementation detail that should not be overly relied on -
if one day some bright spark invented a safe and simple method to automatically minimise precision loss in the un-parenthesised case, I would take it.
Other programming languages may have subtle differences in precedence. For instance, in Python 'or' has a lower precedence than 'and', so take that into account when translating some Python code and Phix starts demanding extra parenthesis. In Python the 'not' operator has a lower precedence than '+', so
idx + not flag + offset
is treated as idx + not (flag + offset)
, quite unlike the Phix
interpretation which is idx + (not flag) + offset
. My recommendation is to use as much parenthesis as you can bear, and when it gets too much
that is as good an excuse as any to break the expression down into more manageable pieces. Besides, storing partial results in appropriately named variables
can not only make the intent much clearer but also make debugging significantly easier and faster, and does not normally incur any additional penalty whatsoever
over the hidden unnamed temporary variable that the compiler would otherwise use anyway.