[swift-evolution-announce] [Review] SE-0077: Improved operator declarations


(Anton Zhilin) #1

Thanks Brent,

I managed to confuse at least two people! I've stated it in the grammar,
but forgot to give an example:

===begin===
Multiple precedence relationships can be stated for a single precedence
group. Example:

precedencegroup A { }
precedencegroup C { }
precedencegroup B { precedence(> A) precedence(< C) }

By transitivity, precedence of C becomes greater than precedence of A.
===end===

As you can see, your suggested syntax would not look good, because there
can be any number of precedence declarations.

But I agree that bulkiness of my syntax is a problem.
I can think of two solutions:

1. Global-scope precedence relationships. Example:

precedencegroup B : associativity(left)
precedencerelation B > A
precedencerelation B < C
infix operator <$> : B

It's already included as an alternate solution.

2. Limit precedence relationships.

Do we really need a full-blown Directed Acyclic Graph?
Could `above` and `between` be enough?

Example:

precedencegroup B : between(A, C)

This is one of dark places of the proposal, obviously underdiscussed.
Are there practical situations other than `above` and `between`?
Do we really need unlimited relationships per one precedencegroup?

- Anton

Brent Royal-Gordon wrote:

···

I like this proposal, except for the `precedencegroup` syntax, which I
think is a bit overwrought. Rather than this proposal's:
precedencegroup Multiplicative {
associativity(left)
precedence(> Additive)
}
I would prefer to see:
precedence Multiplicative > Additive left
(Or possibly, if the `left` is deemed too inexplicable by itself,
`associativity(left)`.) I don't really think the `precedence` keyword or
the curly brackets bring much to the declaration, and dropping them allows
us to replace the awkward compound `precedencegroup` with the shorter and
equally explanatory `precedence`.


(Brent Royal-Gordon) #2

I managed to confuse at least two people! I've stated it in the grammar, but forgot to give an example:

===begin===
Multiple precedence relationships can be stated for a single precedence group. Example:

precedencegroup A { }
precedencegroup C { }
precedencegroup B { precedence(> A) precedence(< C) }

By transitivity, precedence of C becomes greater than precedence of A.
===end===

As you can see, your suggested syntax would not look good, because there can be any number of precedence declarations.

Ah, I see.

2. Limit precedence relationships.

Do we really need a full-blown Directed Acyclic Graph?
Could `above` and `between` be enough?

Example:

precedencegroup B : between(A, C)

This is one of dark places of the proposal, obviously underdiscussed.
Are there practical situations other than `above` and `between`?
Do we really need unlimited relationships per one precedencegroup?

We probably do if you're serious about having operators whose precedence relative to each other is undefined. Moreover, you actually have to be prepared for *more than* two relationships, or two relationships which are both on the same "side", so "between" doesn't cut the mustard.

I can see three ways to fit multiple relationships on one line:

1. precedence Multiplicative > Additive < BitwiseShift left
2. precedence Multiplicative > Additive, < BitwiseShift left
3. precedence Multiplicative > Additive, Multiplicative < BitwiseShift left

Another option would be to have `precedence` lines declare-or-redeclare *all* of the precedence levels in them, not just the one on the left of the operator. Then you would write something like:

4. precedence @associativity(left) Multiplicative > Additive
  precedence Multiplicative < BitwiseShift

It would be an error to have two `precedence` lines which marked the same precedence level with a different `@associativity`. Of course, we could instead put associativity on its own line, perhaps allowing multiple declarations for compactness:

5. precedence Multiplicative > Additive
  precedence Multiplicative < BitwiseShift
  associativity left Cast, Comparative, Multiplicative, Additive

I think 5 is my preference, but if we want a single-line syntax, I'd probably favor 2.

···

--
Brent Royal-Gordon
Architechies


(Matthew Johnson) #3

Thanks Brent,

I managed to confuse at least two people! I've stated it in the grammar, but forgot to give an example:

===begin===
Multiple precedence relationships can be stated for a single precedence group. Example:

precedencegroup A { }
precedencegroup C { }
precedencegroup B { precedence(> A) precedence(< C) }

By transitivity, precedence of C becomes greater than precedence of A.
===end===

As you can see, your suggested syntax would not look good, because there can be any number of precedence declarations.

But I agree that bulkiness of my syntax is a problem.
I can think of two solutions:

1. Global-scope precedence relationships. Example:

precedencegroup B : associativity(left)
precedencerelation B > A
precedencerelation B < C
infix operator <$> : B

It's already included as an alternate solution.

Your argument against this in the alternatives is compelling. We should avoid this one.

2. Limit precedence relationships.

Do we really need a full-blown Directed Acyclic Graph?
Could `above` and `between` be enough?

Example:

precedencegroup B : between(A, C)

Brainstorming some other options here based on Brent’s syntax

A list:
precedence NewGroup > ExistingGroup, < OtherExistingGroup left

Require braces for multiple precedence levels:
precedence NewGroup {
  left
  > ExistingGroup
  < OtherExistingGroup
}

I think my preference is this “lightweight” braced option when multiple relations are necessary, with Brent’s syntax as a shorthand for the common case.

This is one of dark places of the proposal, obviously underdiscussed.
Are there practical situations other than `above` and `between`?
Do we really need unlimited relationships per one precedence group?

I don’t have a concrete example, but those would not allow you to place a group above two unrelated groups. I can’t think of a good reason for this restriction unless there are implementation considerations that make it necessary.

···

On May 19, 2016, at 3:07 PM, Антон Жилин via swift-evolution <swift-evolution@swift.org> wrote:

- Anton

Brent Royal-Gordon wrote:
I like this proposal, except for the `precedencegroup` syntax, which I think is a bit overwrought. Rather than this proposal's:
  precedencegroup Multiplicative {
    associativity(left)
    precedence(> Additive)
  }
I would prefer to see:
  precedence Multiplicative > Additive left
(Or possibly, if the `left` is deemed too inexplicable by itself, `associativity(left)`.) I don't really think the `precedence` keyword or the curly brackets bring much to the declaration, and dropping them allows us to replace the awkward compound `precedencegroup` with the shorter and equally explanatory `precedence`.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Matthew Johnson) #4

I managed to confuse at least two people! I've stated it in the grammar, but forgot to give an example:

===begin===
Multiple precedence relationships can be stated for a single precedence group. Example:

precedencegroup A { }
precedencegroup C { }
precedencegroup B { precedence(> A) precedence(< C) }

By transitivity, precedence of C becomes greater than precedence of A.
===end===

As you can see, your suggested syntax would not look good, because there can be any number of precedence declarations.

Ah, I see.

2. Limit precedence relationships.

Do we really need a full-blown Directed Acyclic Graph?
Could `above` and `between` be enough?

Example:

precedencegroup B : between(A, C)

This is one of dark places of the proposal, obviously underdiscussed.
Are there practical situations other than `above` and `between`?
Do we really need unlimited relationships per one precedencegroup?

We probably do if you're serious about having operators whose precedence relative to each other is undefined. Moreover, you actually have to be prepared for *more than* two relationships, or two relationships which are both on the same "side", so "between" doesn't cut the mustard.

I can see three ways to fit multiple relationships on one line:

1. precedence Multiplicative > Additive < BitwiseShift left
2. precedence Multiplicative > Additive, < BitwiseShift left
3. precedence Multiplicative > Additive, Multiplicative < BitwiseShift left

Another option would be to have `precedence` lines declare-or-redeclare *all* of the precedence levels in them, not just the one on the left of the operator. Then you would write something like:

4. precedence @associativity(left) Multiplicative > Additive
  precedence Multiplicative < BitwiseShift

It would be an error to have two `precedence` lines which marked the same precedence level with a different `@associativity`. Of course, we could instead put associativity on its own line, perhaps allowing multiple declarations for compactness:

5. precedence Multiplicative > Additive
  precedence Multiplicative < BitwiseShift
  associativity left Cast, Comparative, Multiplicative, Additive

I think 5 is my preference, but if we want a single-line syntax, I'd probably favor 2.

The problem with 5 is that the declaration can be spread out in code (especially if you really want to declare associativity of several groups together).

The advantage of this approach is that if you wanted / needed to declare precedence relation of two groups imported from different modules you could do that.

How do you feel about the idea of making single line declaration a shorthand, and using braces with lightweight syntax when multiple relations are necessary? I think that is my preference (unless we decide we need the advantage of your #5 that I described).

···

On May 19, 2016, at 3:36 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Anton Zhilin) #5

OK, question 2 closed, we do need unlimited relationships.
Some critique to Brent's options:
1. No separators, with multiple relations it becomes unobvious, which
comparison corresponds to which group
2. `left` appears suddenly, it may not be clear that it is associativity
3. Where is declaration of the precedence group? It looks like two
relationship declarations, but in Swift, all entities tend to be
pre-declared
4. Remove @, otherwise not that bad
5. Actually, that was the very first version of the proposal. Over time, it
morphed to version in alternative solutions:

precedencegroup B : associativity(left)
precedencerelation B > A
precedencerelation B < C

The specific syntax is discussable:

precedencegroup associativity(left) B
precedence B > A
precedence B < C

We could also stretch inheritance-like syntax:

precedence B : associativity(left), above(A), below(C)

That is my current favourite among one-liners, if we don't want separate
relationship declaration.

On Matthew's version: I like that it is lightweight, but I don't like that
`left` is a "sudden" word again, and that relationships turn into a mess
when written on a single line.

- Anton

···

2016-05-19 23:36 GMT+03:00 Brent Royal-Gordon <brent@architechies.com>:

> I managed to confuse at least two people! I've stated it in the grammar,
but forgot to give an example:
>
> ===begin===
> Multiple precedence relationships can be stated for a single precedence
group. Example:
> ```swift
> precedencegroup A { }
> precedencegroup C { }
> precedencegroup B { precedence(> A) precedence(< C) }
> ```
> By transitivity, precedence of C becomes greater than precedence of A.
> ===end===
>
> As you can see, your suggested syntax would not look good, because there
can be any number of precedence declarations.

Ah, I see.

> 2. Limit precedence relationships.
>
> Do we really need a full-blown Directed Acyclic Graph?
> Could `above` and `between` be enough?
>
> Example:
>
> precedencegroup B : between(A, C)
>
> This is one of dark places of the proposal, obviously underdiscussed.
> Are there practical situations other than `above` and `between`?
> Do we really need unlimited relationships per one precedencegroup?

We probably do if you're serious about having operators whose precedence
relative to each other is undefined. Moreover, you actually have to be
prepared for *more than* two relationships, or two relationships which are
both on the same "side", so "between" doesn't cut the mustard.

I can see three ways to fit multiple relationships on one line:

1. precedence Multiplicative > Additive < BitwiseShift left
2. precedence Multiplicative > Additive, < BitwiseShift left
3. precedence Multiplicative > Additive, Multiplicative <
BitwiseShift left

Another option would be to have `precedence` lines declare-or-redeclare
*all* of the precedence levels in them, not just the one on the left of the
operator. Then you would write something like:

4. precedence @associativity(left) Multiplicative > Additive
        precedence Multiplicative < BitwiseShift

It would be an error to have two `precedence` lines which marked the same
precedence level with a different `@associativity`. Of course, we could
instead put associativity on its own line, perhaps allowing multiple
declarations for compactness:

5. precedence Multiplicative > Additive
        precedence Multiplicative < BitwiseShift
        associativity left Cast, Comparative, Multiplicative, Additive

I think 5 is my preference, but if we want a single-line syntax, I'd
probably favor 2.

--
Brent Royal-Gordon
Architechies


(Matthew Johnson) #6

OK, question 2 closed, we do need unlimited relationships.
Some critique to Brent's options:
1. No separators, with multiple relations it becomes unobvious, which comparison corresponds to which group
2. `left` appears suddenly, it may not be clear that it is associativity
3. Where is declaration of the precedence group? It looks like two relationship declarations, but in Swift, all entities tend to be pre-declared
4. Remove @, otherwise not that bad
5. Actually, that was the very first version of the proposal. Over time, it morphed to version in alternative solutions:

precedencegroup B : associativity(left)
precedencerelation B > A
precedencerelation B < C

The specific syntax is discussable:

precedencegroup associativity(left) B
precedence B > A
precedence B < C

We could also stretch inheritance-like syntax:

precedence B : associativity(left), above(A), below(C)

That is my current favourite among one-liners, if we don't want separate relationship declaration.

On Matthew's version: I like that it is lightweight, but I don't like that `left` is a "sudden" word again, and that relationships turn into a mess when written on a single line.

I suggested adopting two variants. Use Brent's original syntax for single relation declarations and use the multi-line braced variant for multiple relations. We could require the new line separator in the braced version.

If you don't want to have left unadorned maybe we do this for the shorthand:

precedence B > A associativity left

And this for multiple relations:

precedence C {
    > A
    < B
    associativity left
}

In the multiple relation option we could allow associativity to appear at any position in the list or require it to be last for consistency with the single line syntax.

···

Sent from my iPad

On May 19, 2016, at 4:07 PM, Антон Жилин <antonyzhilin@gmail.com> wrote:

- Anton

2016-05-19 23:36 GMT+03:00 Brent Royal-Gordon <brent@architechies.com>:

> I managed to confuse at least two people! I've stated it in the grammar, but forgot to give an example:
>
> ===begin===
> Multiple precedence relationships can be stated for a single precedence group. Example:
> ```swift
> precedencegroup A { }
> precedencegroup C { }
> precedencegroup B { precedence(> A) precedence(< C) }
> ```
> By transitivity, precedence of C becomes greater than precedence of A.
> ===end===
>
> As you can see, your suggested syntax would not look good, because there can be any number of precedence declarations.

Ah, I see.

> 2. Limit precedence relationships.
>
> Do we really need a full-blown Directed Acyclic Graph?
> Could `above` and `between` be enough?
>
> Example:
>
> precedencegroup B : between(A, C)
>
> This is one of dark places of the proposal, obviously underdiscussed.
> Are there practical situations other than `above` and `between`?
> Do we really need unlimited relationships per one precedencegroup?

We probably do if you're serious about having operators whose precedence relative to each other is undefined. Moreover, you actually have to be prepared for *more than* two relationships, or two relationships which are both on the same "side", so "between" doesn't cut the mustard.

I can see three ways to fit multiple relationships on one line:

1. precedence Multiplicative > Additive < BitwiseShift left
2. precedence Multiplicative > Additive, < BitwiseShift left
3. precedence Multiplicative > Additive, Multiplicative < BitwiseShift left

Another option would be to have `precedence` lines declare-or-redeclare *all* of the precedence levels in them, not just the one on the left of the operator. Then you would write something like:

4. precedence @associativity(left) Multiplicative > Additive
        precedence Multiplicative < BitwiseShift

It would be an error to have two `precedence` lines which marked the same precedence level with a different `@associativity`. Of course, we could instead put associativity on its own line, perhaps allowing multiple declarations for compactness:

5. precedence Multiplicative > Additive
        precedence Multiplicative < BitwiseShift
        associativity left Cast, Comparative, Multiplicative, Additive

I think 5 is my preference, but if we want a single-line syntax, I'd probably favor 2.

--
Brent Royal-Gordon
Architechies