[swift-evolution] [Draft] Resolving operator precedence conflicts

Антон Жилин antonyzhilin at gmail.com
Tue Mar 8 14:13:34 CST 2016

There have been complaints on current syntax of operator declarations:

infix operator <> { associativity left precedence 100 assignment }

It looks like a collection of random words. Dictionary syntax would suit
better here. Additionally, `assignment` has been deprecated for a long
time, but not removed.

Many syntaxes were suggested. For example:

#operator(<>, fixity: infix, associativity: left, precedence: 100)

*But* Joe Groff uncovered a deeper problem. Current operators cannot be
given precedence and associativity per concrete operator function.

Moreover, it makes more sense for operators to only allow parenthesis
omission for some other operators. (C/C++ gives warnings for relying on
precedence for unrelated operators.)

Operator declarations may lie in different modules and not know anything
about each other, but they will create a conflict if their names happen to
be identical.

The following is my attempt at solving the problem.

All operators are aliases for functions.

#operator(+, name: numericAdd, fixity: infix, associativity: left)

func numericAdd(left: Int, _ right: Int) -> Int

#operator(+, name: numericUnaryPlus, fixity: prefix)

func unaryPlus(right: Int) -> Int

+1 + 2  // same as numericAdd(numericUnaryPlus(1), 2)

Operators with same "operator form" use overloading, modified to accomodate
associativity and precedence.

#operator(+, name: append, fixity: infix)

func append<T>(left: [T], right: T) -> [T]

var arr = [1, 2, 3]
1 + 2 + 3  //=> 6
[1, 2] + 3  //=> 1 2 3
[1, 2] + 3 + 4  // error

Compiler must try to apply rules of both `numericAdd` and `append` in all
combinations. Complexity of this should not be exponential: most branches
will be cut off fast, starting from the inside.

In 1 + 2 + 3, `append` cannot be applied both to 1+2 and to 2+3, so we are
left with `numericAdd`.
In [1,2] + 3 + 4, `numericAdd` cannot be applied to [1,2] + 3, and `append`
cannot be applied to 3 + 4. But if we assume `append` and `numericAdd`,
then no precedence rule is defined between `numericAdd` and `append`.

Overall, algorithm for compiler is to be developed.

Operators can define precedence (omission of parentheses), only compared to
other specific operators.

#precedence(append, lessThan: numericAdd)

#precedence(numericAdd, equalTo: numericSubtract)

Precedence applies to unary operators as well:

let v: Bool? = false
let u = !v!  // error, precedence between logicalNot and forceUnwrap is not

#precedence(forceUnwrap, greaterThan: logicalNot)

let u = !v!  // true

That said, precedence of unary operators is always higher than of any
binary operator.

- Anton
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160308/ce5430f1/attachment.html>

More information about the swift-evolution mailing list