[swift-evolution] [Proposal] Custom operators

Антон Жилин antonyzhilin at gmail.com
Sun Apr 3 05:45:48 CDT 2016


> Assuming these are defined in separate modules, how do we determine the
order of • and ~?

By default, priority between any two operators is undefined. If two modules
don't know about each other, but the user wishes to prioritize them, then
he will write:

#precedence(•, lessThan: ~)

If • suddenly wishes to cooperate with ~, then it will add directives:

#operator(~, fixity: infix, associativity: left)
#precedence(•, lessThan: ~)

It doesn't matter if ~ or user have already added them: if they do not
contain contradictory information, there will be no conflict.

> 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?

That's exactly what I'm trying to do! I propose that there should be no
hierarchy. Each pair of operators will have to define priority explicitly,
if they need it.

I'll give an example of what I mean by "removing hierarchy":

#precedence(+, lessThan: *)
#precedence(*, lessThan: ^)
2 ^ 3 + 6   # error
#precedence(+, lessThan: ^)
2 ^ 3 + 6   # now ok

- Anton

2016-04-03 13:31 GMT+03:00 Haravikk <swift-evolution at haravikk.me>:

> 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 at 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 at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160403/f5e299ed/attachment.html>


More information about the swift-evolution mailing list