Interesting, I like the idea of changing how precedence is defined, but
I’m curious how under the new scheme we would go about inserting a new
operator unambiguously? For example:
#precedence(•, lessThan: *)
#precedence(~, lessThan: *)
Assuming these are defined in separate modules, how do we determine the
order of • and ~?
On a related note, I never encounter precedence issues because I always
use parenthesis, since I know I’ll just forget the precedence rules so it’d
be a mistake for me to rely on them. If we’re adding operators in
precedence hierarchies then that only makes it even harder to
learn/remember, so I wonder if we might actually be better served by
removing precedence entirely? i.e- the compiler would instead require the
use of parenthesis to eliminate ambiguity like so:
let a = 5 + 6 // Correct, as there aren’t enough operators for ambiguity
let b = 5 + 6 * 7 + 8 // Incorrect, as it relies on precedence to be
meaningful
let c = (5 + 6) * (7 + 8) // Correct, as parenthesis eliminates
ambiguity/the need for precedence
This not only eliminates the need to learn, remember and/or lookup
precedence, but it’s clearer and avoids mistakes, and IMO it’s actually
more readable despite the added noise.
On 3 Apr 2016, at 10:36, Антон Жилин via swift-evolution < > swift-evolution@swift.org> wrote:
Swift 2.2 is out, and I restart discussion on syntax for custom operators.
I insist that this time we should focus less on linguistic aspects.
https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md
Introduction
Replace syntax of operator definition:
infix operator <> { precedence 100 associativity left }
With a directive:
#operator(<>, fixity: infix, associativity: left)
Also replace numeric definition of precedence with separate comparative
precedence definitions:
#precedence(+, lessThan: *)
#precedence(+, equalTo: -)
Swift-evolution thread: link to the discussion thread for that proposal
<https://lists.swift.org/pipermail/swift-evolution>
<https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md#motivation>
Motivation
<https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md#problems-with-numeric-definition-of-precedence>Problems
with numeric definition of precedence
In the beginning, operators had nice precedence values: 90, 100, 110, 120,
130, 140, 150, 160.
As time went, new and new operators were introduced. Precedence could not
be simply changed, as this would be a breaking change. Ranges got
precedence 135, as got precedence 132. ?? had precedence greater than <,
but less thanas, so it had to be given precedence 131.
Now it is not possible to insert any custom operator between < and ??. It
is an inevitable consequence of current design: it will be impossible to
insert an operator between two existing ones at some point.
<https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md#problems-with-a-single-precedence-hierarchy>Problems
with a single precedence hierarchy
Currently, if an operator wants to define precedence by comparison to one
operator, it must do so for all other operators.
In many cases, this is not wished. Example: a & b < c is a common error
pattern. a / b as Double is another one. C++ compilers sometimes emit
warnings on these. Swift does not.
The root of the problem is that precedence is defined between all
operators. If & had precedence defined only by comparison to other
bitwise operators and / – only to arithmetic operators, we would have to
place parentheses in such places, not get subtle bugs, and not ever have to
look at the huge operator precedence table.
<https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md#problems-with-current-operator-definition-syntax>Problems
with current operator definition syntax
Some argue that current operator syntax is not consistent with other
language constructs. Properties of operators have dictionary semantics and
should be defined as such. It is a rather weak argument right now, but
after reworking of precedence, the new syntax will be more to place. More
reasons are given below.
<https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md#conflicts-of-operator-definitions>Conflicts
of operator definitions
Consider two operator definitions in different modules.
Module A:
infix operator |> { precedence 137 associativity left }
Module B:
infix operator |> { precedence 138 associativity left }
<https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md#proposed-solution>Proposed
solution
<https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md#change-syntax-for-operator-definition>Change
syntax for operator definition
#operator(<>, fixity: infix, associativity: left)
#operator(!, fixity: postfix)
First parameter of #operator directive is name of the operator. Then goes
required parameter fixity that can be infix,prefix, or postfix. Then, for
infix operators, goes optional associativity parameter that can be left
or right.
<https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md#comparative-precedence>Comparative
precedence
Remove precedence property from operator definitions. Instead, introduce
#precedence directive:
#precedence(+, lessThan: *)
#precedence(*, equalTo: /)
Omission of parentheses is allowed only when precedence between the two
operators is defined.
1 + 2 * 3 // ok1 + 2 - 3 // error!
#precedence(-, equalTo: +)1 + 2 - 3 // now ok
Precedence equality can only be defined for operators with same
associativity.
<https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md#conflict-resolution>Conflict
resolution
Precedence rules can be added freely across modules. Ability to omit
parentheses around more operators will not break any code in included
modules. On the other hand, conflicting precedence rules result in an error:
#precedence(*, lessThan: +) // error, previously defined `+` < `*`
Operator definitions do nut cause conflicts, unless they are infix and
one of them has associativity: left, but another one has associativity:
right.
#operator(!, fixity: prefix) // ok, duplicated definitions
#operator(<>, fixity: infix)
#operator(<>, fixity: infix, associativity: left) // ok, now left associative
#operator(+, fixity: infix, associativity: right) // error: associativity conflict
So, if two modules define a custom operator with somewhat similar
semantics (at least associativity), they can be used together. Prefix and
postfix operators can never have conflicts in definitions. If they define
different precedence by comparison to same operators, then, most probably,
they had completely different semantics, and the situation is similar to
conflict of functions.
<https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md#detailed-design>Detailed
design
operator keyword and local keywords associativity, precedence, left, right will
be removed.
Directives with following (informal) syntax will be added:
#operator(OPERATOR_NAME, fixity: FIXITY)
#operator(OPERATOR_NAME, fixity: infix, associativity: ASSOCIATIVITY)
#precedence(OPERATOR_NAME, lessThan: OPERATOR_NAME)
#precedence(OPERATOR_NAME, equalTo: OPERATOR_NAME)
<https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md#impact-on-existing-code>Impact
on existing code
Standard library operator declarations will need to be rewritten. Some of
the existing precedence rules will need to be rewritten using #precedence
directive.
More importantly, it needs to be discussed what operator precedence rules
do *not* need to be retained.
User defined operators will need to be rewritten as well. But precedence
will have to be defined by the user. Meanwhile, we can automatically insert
parentheses to user code where needed.
<https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md#alternatives-considered>Alternatives
considered
<https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md#leave-current-operator-syntax-but-change-precedence>Leave
current operator syntax (but change precedence)
#precedence does not make sense to be defined inside of operator
definition, as it describes relationship of two operators. If so, then we
are left with the following declaration syntax:
prefix operator ! { }infix operator |> { }infix operator <> { associativity left }
If body of operator can only contain associativity (in some cases), then
the existence of body itself makes no sense.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution