[Discussion/Draft] Allow Precedence For Prefix And Postfix Operators


(Daniel Duan) #1

Hi all,

I'd like to be able to specify precedence for custom pre/postfix operators.
What's your opinion? I'll let a draft of my proposal say the rest.

···

---

# Allow Specifying Precedence For Prefix And Postfix Operators

* Proposal: TBD
* Author(s): [Daniel Duan](https://github.com/dduan)
* Status: **Awaiting review**
* Review manager: TBD

## Introduction

Swift allows users to specify precedence for infix custom operators but not
for prefix and postfix operators. This Proposal extends prefix and postfix
operator declaration syntax to include a precedence specifier.

## Motivation

Operators compose expressions. Precedence affects the result of such
composition. Prefix and postfix operators are not different from infix
operator in this regard. Without the ability to specify a precedence, users
have to rely on understanding of default precedence value and parenthesis to
work with their costume prefix and postfix operators.

For example, user might need to extend the range operator `..<` to support
a `OpenRange` type, which represent a range with only one end specified with
an integer:

prefix operator ..< {}
prefix func ..<(end: Int) -> HalfRange { // … }

The user might want the following to mean `..< (someNumber + 3)` instead of
`(..< someNumber) + 3`, but they need the ability to say `..<` has higher
precedence than `+`.

let x = ..< someNumber + 3

Hence the need for enabling precedence specification for prefix and postfix
operators.

## Proposed solution

Modify syntax for specifying both prefix and postfix operators. Add the
*precedence* specifier, as it exists for infix operators.

## Detailed design

The Swift compiler will implement the updated prefix and postfix operation
declaration syntax as the following:

prefix-operator-declaration → prefix­operator­operator { [precedence-clause] }­
postfix-operator-declaration → prefix­operator­operator { [precedence-clause] }­

Omitting *precedence-clause* means giving the declared operator a default
precedence value.

## Impact on existing code

None. This change is purely additive.

## Alternatives considered

TBD


(Daniel Duan) #2

Daniel Duan via swift-evolution <swift-evolution@...> writes:

Hi all,

I'd like to be able to specify precedence for custom pre/postfix operators.
What's your opinion? I'll let a draft of my proposal say the rest.

Found some issue in the original draft. I'll be updating it here:
http://bit.ly/1T4jvos


(Chris Lattner) #3

Hi all,

I'd like to be able to specify precedence for custom pre/postfix operators.
What's your opinion? I'll let a draft of my proposal say the rest.

I’m supportive of solving this problem, but have a few comments below:

## Motivation

Operators compose expressions. Precedence affects the result of such
composition. Prefix and postfix operators are not different from infix
operator in this regard. Without the ability to specify a precedence, users
have to rely on understanding of default precedence value and parenthesis to
work with their costume prefix and postfix operators.

For example, user might need to extend the range operator `..<` to support
a `OpenRange` type, which represent a range with only one end specified with
an integer:

prefix operator ..< {}
prefix func ..<(end: Int) -> HalfRange { // … }

The user might want the following to mean `..< (someNumber + 3)` instead of
`(..< someNumber) + 3`, but they need the ability to say `..<` has higher
precedence than `+`.

let x = ..< someNumber + 3

Keep in mind that prefix operators *must* be closely bound (without whitespace) to their operand. Your example will produce "error: unary operator cannot be separated from its operand”.

Given this, I’d strongly opposed to having:

  let x = ..<someNumber + 3

parse with the unary operator less tightly bound than the binary operator it works with. Also keep in mind that unspaced binary operators cannot be juxtaposed without whitespace next to a unary operator. More specifically, this is not allowed:

  let x = someNumber+..<3

you have to write it as:

  let x = someNumber + ..<3

and again, I’d be pretty strongly opposed to having the unary operator bind looser than the infix operator. This example also raises the issue of what this means for a prefix unary operator the on RHS of a tighter binding binary operator.

In any case, a proposal to add precedence to unary operators should tackle these issues. If we allowed whitespace between a unary operator and its operand, that itself would introduce a different host of parsing issues that would have to be solved.

The Swift compiler will implement the updated prefix and postfix operation
declaration syntax as the following:
```
prefix-operator-declaration → prefix­operator­operator { [precedence-clause] }­
postfix-operator-declaration → prefix­operator­operator { [precedence-clause] }­

This style is consistent with our existing stuff, but I’ll observe that our existing “magic number” approach to precedence levels is pretty sad in general :-).

We’ve talked about (but never had time to design and implement) an approach where operators are defined as a partial order (lattice), and the compiler sorted out their relative precedence levels from this declarative spec.

-Chris

···

On Feb 28, 2016, at 5:25 PM, Daniel Duan via swift-evolution <swift-evolution@swift.org> wrote: