Designing a programming language, I'm including the ** exponentiation operator. In Fortran and Python, the two languages I know of which have this operator, it binds more tightly than unary minus, which makes sense for practicality as well as tradition.

It should bind more loosely than the prefix increment operator ++ because the other way wouldn't make sense. Thus the usual single precedence level for the prefix unary operators gets split in two, which is fine as far as it goes.

I'm also including the logical and bitwise not operators ! and ~. Which side of the split should they fall on? Should they bind more loosely or tightly than **? I haven't been able to find either objective reason or relevant precedent for either choice. Is there any of either that I'm missing? Failing that, which would people find less surprising?

  • In math unary - has a lower precedence, I know this from the endless array of ACT questions that try to trick you with - x^2 vs (-x)^2 Sep 26, 2013 at 7:50
  • 4
    If you're really concerned about making a graceful language without surprises, drop pre/post increment operators entirely. Sep 26, 2013 at 23:59
  • 1
    KISS. A rule like "all unary operators take precedence over all binary ones" is much easier to remember than any super-smart rule allowing to save a few chars from time to time.
    – maaartinus
    Sep 27, 2013 at 2:59
  • @Sean McSomething: Or allow them but only on L-values occurring exactly once?
    – maaartinus
    Sep 27, 2013 at 9:47
  • @maaartinus making increment/decrement a statement? Sep 27, 2013 at 16:00

2 Answers 2


When designing a language, you can tweak precedence and other rules to create an elegant experience. Sometimes, not allowing certain constructs can improve readability, without sacrificing much expressiveness. You only loose similarity to other languages, thus making your language harder to learn.

You established -x**y == -(x**y). This makes sense, as this is the convention in maths.

You are considering ++x**y == (++x)**y. The alternative does not make sense, because x**y is not an lvalue. However, you may want to consider disallowing increment on an expression level. E.g. Go takes this route. This avoids the problem that x = ++x is undefined behaviour in many languages. Also, x++**y is downright ugly ;-)

If you have a static type system and a boolean type, then specifying precedence between ** and ! does not make sense: One is a numeric operator, the other is logical.
If you have no boolean type, or no static type system, then ! should have lower precedence, so !x**y is !(x**y). Exponentiation should bind very tightly, only increment and method calls should have higher precedence. Also, the interpretation (!x)**y is wonky: Few would expect that, and you should generally follow the principle of least surprise. This would also give ! a higher precedence than unary minus…

I personally am a fan of alphabetic logical operators like not, and, or with very low precedence. This can improve readability.

I am not a fan of bitwise operators like <<, ~, & because bit twiddling is only useful in very few domains and these characters would be valuable for other operators. << could be some stream operator, ~ could be string concatenation. Look into Haskell or Perl6 for cute ideas.

If you want to include bitwise operators, then they should relate in precedence to their logical equivalents: ! and ~ might have same precedence. ^ (xor) and | should have roughly same precedence, and bind slightly more tightly than the logical operators || and &&. & should have higher precedence than |, just like && usually has higher precedence than ||.

To avoid suprises, stay near C, as it is one of the most influential languages. You can find a precedence table on Wikipedia. Compare with Perl, Python. Also remember that some languages in the ML family survive without such elaborate precedence tables.

  • I've never understood the need some people seem to have for coming up with exotic string concatenation operators. + works just fine. Some people complain that it doesn't make sense mathematically, but that's a silly argument because strings aren't math in the first place, and it does make sense intuitively in the sense of "taking this with that and producing a result that is equal to the two inputs combined together." Sep 27, 2013 at 0:02
  • 4
    @MasonWheeler Strings are math, just like many other CS topics (math > algebra). In fact, it has theoretical semantics closer to multiplication. In practice, it is often favorable if concatenation has lower precedence than multiplication and addition. A separate concatenation operator can provide this. In languages that coerce from and to strings, combined addition and concatenation is ambiguous. One operator should not do two unrelated things.
    – amon
    Sep 27, 2013 at 0:25
  • That just means that JavaScript is poorly designed. (But we knew that already.) And what do you mean that concatenation is more like multiplication, semantically speaking, than addition? I don't see that at all. Sep 27, 2013 at 0:29
  • @MasonWheeler I was wrong. I'm sorry, I just looked up the relevant properties, and concat (over strings) is of course totally unlike both addition and multiplication (over reals): it is not associative, and does not have a zero element. Ergo neither multiplication nor addition operators should be ursurped for strings. My original JS example was shitty; in many languages 1+2+"3" is "33", but "1"+2+3 is "123". The only “correct” result would be a type error, or 6 in some coercive type systems.
    – amon
    Sep 27, 2013 at 1:26
  • @amon: Sure does concatanation have a neutral element: the empty string. So it's like multiplication, but I don't believe using * wouldn't be any better than +. I fully agree with forbidding things like 1+2+"3"!
    – maaartinus
    Sep 27, 2013 at 2:56

I don't have anything to back it up, but my feeling tells me that the logical and bitwise negation operators (! and ~) are most closely related to the unary minus (-) and should have the same precedence level.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.