[Proposal] Custom operators

Apr 5, 2016, Maximilian Hünenberger wrote:

<javascript:_e(%7B%7D,'cvml','antonyzhilin@gmail.com');>>:

Is it OK to have "less, equal, greater" in precedence name?

What do you mean by OK? Other operators like == are weird:

precedence(== == <)
// in comparison to
precedence(== equalTo <)

I meant, are names `precedenceLessThan`, `precedenceEqualTo` a bit clunky?
Maybe:

associativity(left)
precedence(lessThan: +)
precedence(equalTo: +)

It also solves my concern about dictionary inside braces.

After thinking more about it I came to the conclusion that we should have

something like "precedence groups" where all operators have the same
precedence:

precedenceGroup Additive {
    +, -
}

precedenceGroup Multiplicative {
    *, /
}

precedence(Additive lessThan Multiplicative)

infix operator +- {
    associativity: left
}

extension Additive {
    +-, -+, ++, --
}

Precedence groups have a great benefit of additional symmetry. Transitive
precedence propagation, on the other hand, also has benefits:

1. It does not introduce new entities, just some rules for compiler
2. It does not add new keywords. In your current wording, we have to take
precedence and precedenceGroup as keywords, that's why I
originally preferred directives
3. We actually think in terms of operators, not groups.
If I want to say that my operator should have the same priority as `+`, I'd
rather say that I want it to have priority of plus and minus, not "belong
to multiplicative group".
If I declare <$> and want it to have same priority as <*>, it would be more
difficult to invent some name for their group like FunctorManipulator.

On the other hand, in your solution you have a list of global rules
and don't really need braces. How about this?

#precedenceGroup(Additive)
#precedenceGroup(Multiplicative)
#precedence(Additive, less, Multiplicative)
#operator(+, infix, associativity: left, group: Additive)
#operator(*, infix, associativity: left, group: Multiplicative)
#operator(<>, infix)

So precedence group is just a tag that can be used in precedence rules and
assigned to operators at declaration.

···

Am 04.04.2016 um 08:06 schrieb Антон Жилин <antonyzhilin@gmail.com

David Waite stated a major drawback of precedence groups.

People will often create tiny precedence groups for their modules, and user
will find that some of them should actually be the same. They will add
precedenceEqualTo, but all these equivalent groups will still exist. This
problem cannot occur with transitive precedence propagation. So precedence
groups really create more problems than solve.

- Anton

Apr 5, 2016, Антон Жилин wrote:

···

On the other hand, in your solution you have a list of global rules
and don't really need braces. How about this?

#precedenceGroup(Additive)
#precedenceGroup(Multiplicative)
#precedence(Additive, less, Multiplicative)
#operator(+, infix, associativity: left, group: Additive)
#operator(*, infix, associativity: left, group: Multiplicative)
#operator(<>, infix)

So precedence group is just a tag that can be used in precedence rules and
assigned to operators at declaration.

David Waite stated a major drawback of precedence groups.

People will often create tiny precedence groups for their modules, and user will find that some of them should actually be the same. They will add precedenceEqualTo, but all these equivalent groups will still exist. This problem cannot occur with transitive precedence propagation. So precedence groups really create more problems than solve.

- Anton

Do you mean these drawbacks?

"

However, this may create more issues than it solves (two frameworks creating their own custom operators, putting them in custom precedence groups, and the consumer decides the two precedence groups are really equivalent)

-DW

"

What is the problem? Changing the relative precedence of external operators in your file? Doesn't the same "problem" occur in your proposal (only with one operator)?

What is the difference between overriding an operator function like this:

func + (l: Int, r: Int) -> Int {
       return 0
}

This can also mess up your code...
I'm sorry if I haven't understood your point.

From the other email:

I meant, are names `precedenceLessThan`, `precedenceEqualTo` a bit clunky? Maybe:

associativity(left)
precedence(lessThan: +)
precedence(equalTo: +)

It also solves my concern about dictionary inside braces.

I prefer "precedence(+ lessThan *)". However I don't think it's Swift style since "lessThan" is like an infix operator with letters although the symmetry between "+" and "*" would be nicely handled by such operator.

Precedence groups have a great benefit of additional symmetry. Transitive precedence propagation, on the other hand, also has benefits:

1. It does not introduce new entities, just some rules for compiler
2. It does not add new keywords. In your current wording, we have to take precedence and precedenceGroup as keywords, that's why I originally preferred directives

Both 1 and 2 are true but I still prefer to use declarations since they provide exactly one location where to put operators with equal precedence.

By the way "precedence" is already a keyword... One more to go :)

3. We actually think in terms of operators, not groups.
If I want to say that my operator should have the same priority as `+`, I'd rather say that I want it to have priority of plus and minus, not "belong to multiplicative group".
If I declare <$> and want it to have same priority as <*>, it would be more difficult to invent some name for their group like FunctorManipulator.

I think this deserves more discussion:
Should we allow "precedence(... equalTo ...)" for operators if we have precedence groups?

Such a precedence declaration would be contrary to my argument above: declare equal operator precedences in one place, which is more maintainable.

On the other hand, in your solution you have a list of global rules and don't really need braces. How about this?

#precedenceGroup(Additive)
#precedenceGroup(Multiplicative)
#precedence(Additive, less, Multiplicative)
#operator(+, infix, associativity: left, group: Additive)
#operator(*, infix, associativity: left, group: Multiplicative)
#operator(<>, infix)

So precedence group is just a tag that can be used in precedence rules and assigned to operators at declaration.

Although it is consistent with your proposal for me it is too much repetition and "code noise". Compare:

infix operator + { associativity: left }
infix operator * { associativity: left }
infix operator <> {}
precedenceGroup Additive { + }
precedenceGroup Multiplicative { * }
precedence(Additive lessThan Multiplicative)

Which is in my opinion way more readable even without syntax highlighting.

Thank You for sharing Your thoughts which have enriched me! :)

Best regards
- Maximilian

···

Am 05.04.2016 um 17:29 schrieb Антон Жилин <antonyzhilin@gmail.com>:

Added
<https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md#use-precedence-groups&gt;
group version, "lessThan" problem can be solved nicely. `<`, `=`, `>` signs
would be allowed there.

Should we allow "precedence(... equalTo ...)" for operators if we have

precedence groups?
I think no.

I have a question to your group syntax.
Since all operators in a precedence group must have equal associativity for
parsing to work and look logically (right?), wouldn't it be better to
declare associativity in groups?
If so, then body of operator declaration won't contain anything, and we can
remove it:

precedenceGroup Additive {
    associativity(left)
    +, -
}
infix operator +
infix operator -

Does this body of precedenceGroup look OK from syntactic PoV?

Now, I have another idea.
As operator declarations themselves don't contain anything anymore, remove
operator declarations at all. We don't need to pre-declare function names,
for example.
Next, `precedenceGroup` could be as well replaced with `precedenceLevel`,
or just `precedence`, and I would not worry about additional keywords.
So, our example would look like this:

precedence Additive {
    associativity(left)
    +, -
}
precedence Multiplicative {
    associativity(left)
    *, /
}
precedence(Additive < Multiplicative)

As a future direction, we could add extensions to precedence levels.
We could go further and replace `precedence` with `operator`, abandoning
the idea of priority for prefix and postfix operators (that I honestly
don't like).

infix operator Additive {
    members(+, -)
    associativity(left)
}
infix operator Multiplicative {
    members(*, /)
    associativity(left)
    precedence(> Additive)
}

Some other questions:
Do we need transitive precedence propagation?
Do we need resolution of conflicts, i.e. merging multiple definitions of
same operators and groups, where possible?

···

2016-04-05 22:52 GMT+03:00 Maximilian Hünenberger <m.huenenberger@me.com>:

Am 05.04.2016 um 17:29 schrieb Антон Жилин <antonyzhilin@gmail.com>:

David Waite stated a major drawback of precedence groups.

People will often create tiny precedence groups for their modules, and
user will find that some of them should actually be the same. They will add
precedenceEqualTo, but all these equivalent groups will still exist. This
problem cannot occur with transitive precedence propagation. So precedence
groups really create more problems than solve.

- Anton

Do you mean these drawbacks?

"

However, this may create more issues than it solves (two frameworks
creating their own custom operators, putting them in custom precedence
groups, and the consumer decides the two precedence groups are really
equivalent)

-DW

"

What is the problem? Changing the relative precedence of external
operators in your file? Doesn't the same "problem" occur in your proposal
(only with one operator)?

What is the difference between overriding an operator function like this:

func + (l: Int, r: Int) -> Int {
       return 0
}

This can also mess up your code...
I'm sorry if I haven't understood your point.

From the other email:

I meant, are names `precedenceLessThan`, `precedenceEqualTo` a bit clunky?
Maybe:

associativity(left)
precedence(lessThan: +)
precedence(equalTo: +)

It also solves my concern about dictionary inside braces.

I prefer "precedence(+ lessThan *)". However I don't think it's Swift
style since "lessThan" is like an infix operator *with letters *although
the symmetry between "+" and "*" would be nicely handled by such operator.

Precedence groups have a great benefit of additional symmetry. Transitive
precedence propagation, on the other hand, also has benefits:

1. It does not introduce new entities, just some rules for compiler
2. It does not add new keywords. In your current wording, we have to take
precedence and precedenceGroup as keywords, that's why I
originally preferred directives

Both 1 and 2 are true but I still prefer to use declarations since they
provide exactly one location where to put operators with equal precedence.

By the way "precedence" is already a keyword... One more to go :)

3. We actually think in terms of operators, not groups.
If I want to say that my operator should have the same priority as `+`,
I'd rather say that I want it to have priority of plus and minus, not
"belong to multiplicative group".
If I declare <$> and want it to have same priority as <*>, it would be
more difficult to invent some name for their group like FunctorManipulator.

I think this deserves more discussion:
Should we allow "precedence(... equalTo ...)" for operators if we have
precedence groups?

Such a precedence declaration would be contrary to my argument above:
declare equal operator precedences in one place, which is more maintainable.

On the other hand, in your solution you have a list of global rules
and don't really need braces. How about this?

#precedenceGroup(Additive)
#precedenceGroup(Multiplicative)
#precedence(Additive, less, Multiplicative)
#operator(+, infix, associativity: left, group: Additive)
#operator(*, infix, associativity: left, group: Multiplicative)
#operator(<>, infix)

So precedence group is just a tag that can be used in precedence rules and
assigned to operators at declaration.

Although it is consistent with your proposal for me it is too much
repetition and "code noise". Compare:

infix operator + { associativity: left }
infix operator * { associativity: left }
infix operator <> {}
precedenceGroup Additive { + }
precedenceGroup Multiplicative { * }
precedence(Additive lessThan Multiplicative)

Which is in my opinion way more readable even without syntax highlighting.

Thank You for sharing Your thoughts which have enriched me! :)

Best regards
- Maximilian

Added group version, "lessThan" problem can be solved nicely. `<`, `=`, `>` signs would be allowed there.

> Should we allow "precedence(... equalTo ...)" for operators if we have precedence groups?
I think no.

I have a question to your group syntax.
Since all operators in a precedence group must have equal associativity for parsing to work and look logically (right?), wouldn't it be better to declare associativity in groups?
If so, then body of operator declaration won't contain anything, and we can remove it:

precedenceGroup Additive {
    associativity(left)
    +, -
}
infix operator +
infix operator -

Does this body of precedenceGroup look OK from syntactic PoV?

Associativity in precedence groups is fine however the operators should then be grouped possibly: "operators(+, -)"

Now, I have another idea.
As operator declarations themselves don't contain anything anymore, remove operator declarations at all. We don't need to pre-declare function names, for example.
Next, `precedenceGroup` could be as well replaced with `precedenceLevel`, or just `precedence`, and I would not worry about additional keywords.
So, our example would look like this:

precedence Additive {
    associativity(left)
    +, -
}
precedence Multiplicative {
    associativity(left)
    *, /
}
precedence(Additive < Multiplicative)

As a future direction, we could add extensions to precedence levels.
We could go further and replace `precedence` with `operator`, abandoning the idea of priority for prefix and postfix operators (that I honestly don't like).

Regarding pre- and postfix operators: there was a separate thread which discussed exactly this. The biggest problem was that if a prefix "-" has lower precedence than an infix operator like "^" this calculation is ambiguous from a human perspective:

-3 ^ 3

"-" has visually the higher precedence and the result would be 9. However the actual result is -9.

If we have precedence on pre- and postfix operators we would break existing code. A migratory could then enforce the old precedence levels with braces. But then we can resolve existing (visual) ambiguities and "mathematical incorrectness" by making the precedence of prefix "-" higher than the current comparative operators and not declare its precedence to higher precedence operators (precedence > 140)

Such that this expression is ambiguous to the compiler:

3 - -3 // also mathematically incorrect
// and should be rewritten to
3 - (-3)
// or just
3 + 3

infix operator Additive {
    members(+, -)
    associativity(left)
}
infix operator Multiplicative {
    members(*, /)
    associativity(left)
    precedence(> Additive)
}

Some other questions:
Do we need transitive precedence propagation?

Yes because it would be quite a pain to declare every precedence between all precedence groups:
#needed precedence declarations ~ O(#of precedence groups ^ 2)

Do we need resolution of conflicts, i.e. merging multiple definitions of same operators and groups, where possible?

I think we shouldn't define operators in a precedence group because if we want to have an operator in two different groups then we have two operator definitions which can result in a conflict.
I'm not sure if we need the same operator in different groups. Therefore I'd suggest to declare all standard library operators in this form in order to see if we need this.

So my current syntax suggestion is:

infix operator + { associativity(left) }
prefix operator -
infix operator && { associativity(left) }

infix precedenceGroup Additive {
        associativity(left)
        members(+)
}

infix precedenceGroup Logical {
        associativity(left)
        members(&&)
}

prefix precedenceGroup Sign {
        members(-)
}

precedence(Additive > Logical)
precedence(Sign > Logical)

// warning: duplicate precedence declarations
precedence(Logical < Additive)

···

Am 05.04.2016 um 22:32 schrieb Антон Жилин <antonyzhilin@gmail.com>:

--------

I declare associativity in operator declarations and precedence group declarations since it lets the compiler check whether the "members" have the right associativity.

Best regards
- Maximilian

First of all, sorry for the delay. I still hope to finish the discussion
and push the proposal to review for Swift 3.0.
Link for newcomers:
https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md

Sadly, I've moved into the territory opposite to what I had in mind in the
beginning: absense of conflict resolution.
I wanted lightweight directives, but am moving to closed precedence groups.

It's just IMHO, and I think I just need input on this from more people. I
still have not heard anything from Core team.

My main question would be: maximally "mergeable" directives or closed
declarations?

Now, another iteration of syntax discussion.
I've created a sample of definitions of precedence operators for standard
library, using precedence groups (at the end of the proposal).

There is no evidence that an operator could logically belong to multiple
precedence groups.
Really, precedence groups are just a way of writing multiple identical
operator declarations in a shorter way.

Precedence groups will be closed, meaning that no precedence relations can
be added to them outside of their bodies.
It will make merging all standard library operators in a giant hierarchy
less tempting, although possible.
Still, that would be possible. We could disallow that specifically as a
future direction (only for standard library).

Still, new operators must be able to be added to existing precedence groups.
Extensions cannot be used, because namespaces of types and precedencegroups
will not intersect.
So I have to return to declaration of operators, if noone finds a better
way and if noone objects:

precedencegroup Additive {
    members(+, -)
    associativity(left)
    precedence(> Comparative)
}
infix operator +
infix operator -
infix operator &+ { precedencegroup(Additive) }

All operators must have precedence groups.
I thought of allowing operators to be single-operator precedence groups,
but it wouldn't give any real benefits.
I also thought of allowing operators without precedence, but almost all
operators will want at least `precedence(>Assignment)`.

Now, what questions did arise from standard library operator declarations?

1. All precedence groups have a "parent".
It means, all operators will want to have precedence higher than
Comparative or Ternary, or, at least, Assignment.

2. Moreover, I could not find any case where I had to write anything other
than precedence(>, ...)
Of cause, I cheated, because I can control all these declarations.
Mere people will have to use `<` to say that Additive, for example, should
have less priority than their custom operator.

But... can you build a custom operator where `<` will actually be needed? I
have even stronger doubts on `=`.
Maybe we can even contract this feature to `parent(Comparative)` or
something without losing any expressivity?

3. Can we allow operators to have less priority than `=`?
If yes, can you give an example of such operator?

4. Operators `is`, `as`, `as?`, `as!`, `?:`, `=` are not proper Swift
operators.
But we can still support these tokens for consistency.
Their only appearence would be in the standard library.
Alternatively, we can hide their precedence groups and make them a special
case.
It's more a question of implementation complexity.

5. I removed associativity from Ternary, removed BitwiseXor from bitwise
hierarchy.
And made numerous other changes that probably need to be reviewed.

···

2016-04-06 9:17 GMT+03:00 Maximilian Hünenberger <m.huenenberger@me.com>:

Am 05.04.2016 um 22:32 schrieb Антон Жилин <antonyzhilin@gmail.com>:

Added
<https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md#use-precedence-groups&gt;
group version, "lessThan" problem can be solved nicely. `<`, `=`, `>` signs
would be allowed there.

> Should we allow "precedence(... equalTo ...)" for operators if we have
precedence groups?
I think no.

I have a question to your group syntax.
Since all operators in a precedence group must have equal associativity
for parsing to work and look logically (right?), wouldn't it be better to
declare associativity in groups?
If so, then body of operator declaration won't contain anything, and we
can remove it:

precedenceGroup Additive {
    associativity(left)
    +, -
}
infix operator +
infix operator -

Does this body of precedenceGroup look OK from syntactic PoV?

Associativity in precedence groups is fine however the operators should
then be grouped possibly: "operators(+, -)"

Now, I have another idea.
As operator declarations themselves don't contain anything anymore, remove
operator declarations at all. We don't need to pre-declare function names,
for example.
Next, `precedenceGroup` could be as well replaced with `precedenceLevel`,
or just `precedence`, and I would not worry about additional keywords.
So, our example would look like this:

precedence Additive {
    associativity(left)
    +, -
}
precedence Multiplicative {
    associativity(left)
    *, /
}
precedence(Additive < Multiplicative)

As a future direction, we could add extensions to precedence levels.
We could go further and replace `precedence` with `operator`, abandoning
the idea of priority for prefix and postfix operators (that I honestly
don't like).

Regarding pre- and postfix operators: there was a separate thread which
discussed exactly this. The biggest problem was that if a prefix "-" has
lower precedence than an infix operator like "^" this calculation is
ambiguous from a human perspective:

-3 ^ 3

"-" has visually the higher precedence and the result would be 9. However
the actual result is -9.

If we have precedence on pre- and postfix operators we would break
existing code. A migratory could then enforce the old precedence levels
with braces. But then we can resolve existing (visual) ambiguities and
"mathematical incorrectness" by making the precedence of prefix "-" higher
than the current comparative operators and not declare its precedence to
higher precedence operators (precedence > 140)

Such that this expression is ambiguous to the compiler:

3 - -3 // also mathematically incorrect
// and should be rewritten to
3 - (-3)
// or just
3 + 3

infix operator Additive {
    members(+, -)
    associativity(left)
}
infix operator Multiplicative {
    members(*, /)
    associativity(left)
    precedence(> Additive)
}

Some other questions:
Do we need transitive precedence propagation?

Yes because it would be quite a pain to declare every precedence between
all precedence groups:
#needed precedence declarations ~ O(#of precedence groups ^ 2)

Do we need resolution of conflicts, i.e. merging multiple definitions of
same operators and groups, where possible?

I think we shouldn't define operators in a precedence group because if we
want to have an operator in two different groups then we have two operator
definitions which can result in a conflict.
I'm not sure if we need the same operator in different groups. Therefore
I'd suggest to declare all standard library operators in this form in order
to see if we need this.

So my current syntax suggestion is:

infix operator + { associativity(left) }
prefix operator -
infix operator && { associativity(left) }

infix precedenceGroup Additive {
        associativity(left)
        members(+)
}

infix precedenceGroup Logical {
        associativity(left)
        members(&&)
}

prefix precedenceGroup Sign {
        members(-)
}

precedence(Additive > Logical)
precedence(Sign > Logical)

// warning: duplicate precedence declarations
precedence(Logical < Additive)

--------

I declare associativity in operator declarations and precedence group
declarations since it lets the compiler check whether the "members" have
the right associativity.

Best regards
- Maximilian

First of all, sorry for the delay. I still hope to finish the discussion and push the proposal to review for Swift 3.0.
Link for newcomers:
https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md

Sadly, I've moved into the territory opposite to what I had in mind in the beginning: absense of conflict resolution.
I wanted lightweight directives, but am moving to closed precedence groups.

It's just IMHO, and I think I just need input on this from more people. I still have not heard anything from Core team.

Hi Антон,

I’m sorry for the delay, I have been out of town recently. I haven’t read the upstream thread so I hope this isn’t too duplicative. Here is my 2c:

- I completely agree that numeric precedences are lame, it was always the “plan” that they’d be removed someday, but that obviously still hasn’t happened :-)
- I definitely agree that a partial ordering between precedences is all that we need/want, and that unspecified relations should be an error.

That said, I feel like #operator is a major syntactic regression, both in consistency and predictability. We use # for two things: directives (like if) and for expressions (#file). The #operator is a declaration of an operator, not an expression or a directive. For declarations, we consistently use a keyword, which allows contextual modifiers before them, along with a body (which is sometimes optional for certain kinds of decls). I feel like you’re trying to syntactically reduce the weight of something that doesn’t occur very often, which is no real win in expressiveness, and harms consistency.

Likewise #precedence is a relationship between two operators. I’d suggest putting them into the body of the operator declaration.

OTOH, the stuff inside the current operator declaration is a random series of tokens with no apparent structure. I think it would be reasonable to end up with something like:

infix operator <> {
  associativity: left
  precedenceLessThan: *
  precedenceEqualTo: -
}

Or whatever. The rationale here is that “infix” is primal on the operator decl (and thus is outside the braces) but the rest of the stuff can be omitted, so it goes inside.

Just in terms of the writing of the proposal, in the "Change precedence mechanism” keep in mind that swift code generally doesn’t care about the order of declarations (it doesn’t parse top down in the file like C does) so the example is a bit misleading.

Question for you: have you considered introducing named precedence groups, and having the relationships be between those groups? For example, I could see something like:

  operator group additive {}
  operator group multiplicative { greaterThan: additive }
  operator group exponential { greaterThan: additive }

Then:

infix operator + {
  associativity: left
  precedence: additive
}
infix operator - {
  associativity: left
  precedence: additive
}

etc.

-Chris

···

On Apr 7, 2016, at 1:39 PM, Антон Жилин via swift-evolution <swift-evolution@swift.org> wrote:

Still, new operators must be able to be added to existing precedence groups.
Extensions cannot be used, because namespaces of types and precedencegroups will not intersect.
So I have to return to declaration of operators, if noone finds a better way and if noone objects:

precedencegroup Additive {
    members(+, -)
    associativity(left)
    precedence(> Comparative)
}
infix operator +
infix operator -
infix operator &+ { precedencegroup(Additive) }

All operators must have precedence groups.
I thought of allowing operators to be single-operator precedence groups, but it wouldn't give any real benefits.
I also thought of allowing operators without precedence, but almost all operators will want at least `precedence(>Assignment)`.

Now, what questions did arise from standard library operator declarations?

1. All precedence groups have a "parent".
It means, all operators will want to have precedence higher than Comparative or Ternary, or, at least, Assignment.

2. Moreover, I could not find any case where I had to write anything other than precedence(>, ...)
Of cause, I cheated, because I can control all these declarations.
Mere people will have to use `<` to say that Additive, for example, should have less priority than their custom operator.

But... can you build a custom operator where `<` will actually be needed? I have even stronger doubts on `=`.
Maybe we can even contract this feature to `parent(Comparative)` or something without losing any expressivity?

3. Can we allow operators to have less priority than `=`?
If yes, can you give an example of such operator?

4. Operators `is`, `as`, `as?`, `as!`, `?:`, `=` are not proper Swift operators.
But we can still support these tokens for consistency.
Their only appearence would be in the standard library.
Alternatively, we can hide their precedence groups and make them a special case.
It's more a question of implementation complexity.

5. I removed associativity from Ternary, removed BitwiseXor from bitwise hierarchy.
And made numerous other changes that probably need to be reviewed.

2016-04-06 9:17 GMT+03:00 Maximilian Hünenberger <m.huenenberger@me.com <mailto:m.huenenberger@me.com>>:

Am 05.04.2016 um 22:32 schrieb Антон Жилин <antonyzhilin@gmail.com <mailto:antonyzhilin@gmail.com>>:

Added <https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md#use-precedence-groups&gt; group version, "lessThan" problem can be solved nicely. `<`, `=`, `>` signs would be allowed there.

> Should we allow "precedence(... equalTo ...)" for operators if we have precedence groups?
I think no.

I have a question to your group syntax.
Since all operators in a precedence group must have equal associativity for parsing to work and look logically (right?), wouldn't it be better to declare associativity in groups?
If so, then body of operator declaration won't contain anything, and we can remove it:

precedenceGroup Additive {
    associativity(left)
    +, -
}
infix operator +
infix operator -

Does this body of precedenceGroup look OK from syntactic PoV?

Associativity in precedence groups is fine however the operators should then be grouped possibly: "operators(+, -)"

Now, I have another idea.
As operator declarations themselves don't contain anything anymore, remove operator declarations at all. We don't need to pre-declare function names, for example.
Next, `precedenceGroup` could be as well replaced with `precedenceLevel`, or just `precedence`, and I would not worry about additional keywords.
So, our example would look like this:

precedence Additive {
    associativity(left)
    +, -
}
precedence Multiplicative {
    associativity(left)
    *, /
}
precedence(Additive < Multiplicative)

As a future direction, we could add extensions to precedence levels.
We could go further and replace `precedence` with `operator`, abandoning the idea of priority for prefix and postfix operators (that I honestly don't like).

Regarding pre- and postfix operators: there was a separate thread which discussed exactly this. The biggest problem was that if a prefix "-" has lower precedence than an infix operator like "^" this calculation is ambiguous from a human perspective:

-3 ^ 3

"-" has visually the higher precedence and the result would be 9. However the actual result is -9.

If we have precedence on pre- and postfix operators we would break existing code. A migratory could then enforce the old precedence levels with braces. But then we can resolve existing (visual) ambiguities and "mathematical incorrectness" by making the precedence of prefix "-" higher than the current comparative operators and not declare its precedence to higher precedence operators (precedence > 140)

Such that this expression is ambiguous to the compiler:

3 - -3 // also mathematically incorrect
// and should be rewritten to
3 - (-3)
// or just
3 + 3

infix operator Additive {
    members(+, -)
    associativity(left)
}
infix operator Multiplicative {
    members(*, /)
    associativity(left)
    precedence(> Additive)
}

Some other questions:
Do we need transitive precedence propagation?

Yes because it would be quite a pain to declare every precedence between all precedence groups:
#needed precedence declarations ~ O(#of precedence groups ^ 2)

Do we need resolution of conflicts, i.e. merging multiple definitions of same operators and groups, where possible?

I think we shouldn't define operators in a precedence group because if we want to have an operator in two different groups then we have two operator definitions which can result in a conflict.
I'm not sure if we need the same operator in different groups. Therefore I'd suggest to declare all standard library operators in this form in order to see if we need this.

So my current syntax suggestion is:

infix operator + { associativity(left) }
prefix operator -
infix operator && { associativity(left) }

infix precedenceGroup Additive {
        associativity(left)
        members(+)
}

infix precedenceGroup Logical {
        associativity(left)
        members(&&)
}

prefix precedenceGroup Sign {
        members(-)
}

precedence(Additive > Logical)
precedence(Sign > Logical)

// warning: duplicate precedence declarations
precedence(Logical < Additive)

--------

I declare associativity in operator declarations and precedence group declarations since it lets the compiler check whether the "members" have the right associativity.

Best regards
- Maximilian

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

Link for newcomers:
https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md

Sadly, I've moved into the territory opposite to what I had in mind in the beginning: absense of conflict resolution.
I wanted lightweight directives, but am moving to closed precedence groups.

It's just IMHO, and I think I just need input on this from more people. I still have not heard anything from Core team.

...
I’m sorry for the delay, I have been out of town recently. I haven’t read the upstream thread so I hope this isn’t too duplicative. Here is my 2c:

- I completely agree that numeric precedences are lame, it was always the “plan” that they’d be removed someday, but that obviously still hasn’t happened :-)

+10!

- I definitely agree that a partial ordering between precedences is all that we need/want, and that unspecified relations should be an error.
...
Question for you: have you considered introducing named precedence groups, and having the relationships be between those groups? For example, I could see something like:

  operator group additive {}
  operator group multiplicative { greaterThan: additive }
  operator group exponential { greaterThan: additive }

Also +10, would be interested in your opinion about:

1) disallowing adding new operator groups outside the stdlib;

2) disallowing adding operators to uncommon groups like subscripting,
function calls, etc.

TIA...

···

On 4/8/16 02:59, Chris Lattner via swift-evolution wrote:

On Apr 7, 2016, at 1:39 PM, Антон Жилин via swift-evolution <swift-evolution@swift.org> wrote:

--
Rainer Brockerhoff <rainer@brockerhoff.net>
Belo Horizonte, Brazil
"In the affairs of others even fools are wise
In their own business even sages err."

Thank you for your reply, Chris!
I was thinking about purging directives from the proposal, and that was
what I needed to do it.
So, the proposal is now completely overhauled:
https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md

Yes, Maximilian and I have considered operator/precedence groups and they
have now moved from alternatives to main part of the proposal.

Questions:
1. Is it OK that associativity is moved to precedence groups and that every
operator must belong to a precedence group?
2. Dictionary-like or "functional keywords"? That is, `associativity: left`
or `associativity(left)`? So far, only second form has been used somewhere
inside declarations.
3. First-lower or first-upper? `additive` or `Additive`?
4. Empty body or no body? `prefix operator ! { }` or `prefix operator !`?

Just in case, some questions/concerns copied from previous discussion:

1. All precedence groups have a "parent".
It means, all operators will want to have precedence higher than
Comparative or Ternary, or, at least, Assignment.

2. Moreover, I could not find any case where I had to write anything other
than precedence(>, ...)
Of cause, I cheated, because I can control all these declarations.
Mere people will have to use `<` to say that Additive, for example, should
have less priority than their custom operator.

But... can you build a custom operator where `<` will actually be needed? I
have even stronger doubts on `=`.
Maybe we can even contract this feature to `parent(Comparative)` or
something without losing any expressivity?

3. Can we allow operators to have less priority than `=`?
If yes, can you give an example of such operator?

- Anton

···

2016-04-08 8:59 GMT+03:00 Chris Lattner <clattner@apple.com>:

On Apr 7, 2016, at 1:39 PM, Антон Жилин via swift-evolution < > swift-evolution@swift.org> wrote:

First of all, sorry for the delay. I still hope to finish the discussion
and push the proposal to review for Swift 3.0.
Link for newcomers:

https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md

Sadly, I've moved into the territory opposite to what I had in mind in the
beginning: absense of conflict resolution.
I wanted lightweight directives, but am moving to closed precedence groups.

It's just IMHO, and I think I just need input on this from more people. I
still have not heard anything from Core team.

Hi Антон,

I’m sorry for the delay, I have been out of town recently. I haven’t read
the upstream thread so I hope this isn’t too duplicative. Here is my 2c:

- I completely agree that numeric precedences are lame, it was always the
“plan” that they’d be removed someday, but that obviously still hasn’t
happened :-)
- I definitely agree that a partial ordering between precedences is all
that we need/want, and that unspecified relations should be an error.

That said, I feel like #operator is a major syntactic regression, both in
consistency and predictability. We use # for two things: directives (like
if) and for expressions (#file). The #operator is a declaration of an
operator, not an expression or a directive. For declarations, we
consistently use a keyword, which allows contextual modifiers before them,
along with a body (which is sometimes optional for certain kinds of
decls). I feel like you’re trying to syntactically reduce the weight of
something that doesn’t occur very often, which is no real win in
expressiveness, and harms consistency.

Likewise #precedence is a relationship between two operators. I’d suggest
putting them into the body of the operator declaration.

OTOH, the stuff inside the current operator declaration is a random series
of tokens with no apparent structure. I think it would be reasonable to
end up with something like:

infix operator <> {
  associativity: left
  precedenceLessThan: *
  precedenceEqualTo: -
}

Or whatever. The rationale here is that “infix” is primal on the operator
decl (and thus is outside the braces) but the rest of the stuff can be
omitted, so it goes inside.

Just in terms of the writing of the proposal, in the "Change precedence
mechanism” keep in mind that swift code generally doesn’t care about the
order of declarations (it doesn’t parse top down in the file like C does)
so the example is a bit misleading.

Question for you: have you considered introducing named precedence groups,
and having the relationships be between those groups? For example, I could
see something like:

operator group additive {}
operator group multiplicative { greaterThan: additive }
operator group exponential { greaterThan: additive }

Then:

infix operator + {
  associativity: left
  precedence: additive
}
infix operator - {
  associativity: left
  precedence: additive
}

etc.

-Chris

If I want to define a new operator, it seems like an unnecessary overhead
to have to immediately decide which precedence group it should belong to
before it can be used (assuming it doesn't interact with other operators).
At the moment, new operators are implicitly assigned a 'default' precedence
of 100; can we make it so that new operators are implicitly assigned to a
'default' group with an effective precedence of 100? (I believe this is
currently the precedence of Ternary, but I'm not sure if I'd have Ternary
be the default group).

···

On Fri, Apr 8, 2016 at 5:59 PM, Антон Жилин <swift-evolution@swift.org> wrote:

Thank you for your reply, Chris!
I was thinking about purging directives from the proposal, and that was
what I needed to do it.
So, the proposal is now completely overhauled:

https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md

Yes, Maximilian and I have considered operator/precedence groups and they
have now moved from alternatives to main part of the proposal.

Questions:
1. Is it OK that associativity is moved to precedence groups and that
every operator must belong to a precedence group?
2. Dictionary-like or "functional keywords"? That is, `associativity:
left` or `associativity(left)`? So far, only second form has been used
somewhere inside declarations.
3. First-lower or first-upper? `additive` or `Additive`?
4. Empty body or no body? `prefix operator ! { }` or `prefix operator !`?

Just in case, some questions/concerns copied from previous discussion:

1. All precedence groups have a "parent".
It means, all operators will want to have precedence higher than
Comparative or Ternary, or, at least, Assignment.

2. Moreover, I could not find any case where I had to write anything other
than precedence(>, ...)
Of cause, I cheated, because I can control all these declarations.
Mere people will have to use `<` to say that Additive, for example, should
have less priority than their custom operator.

But... can you build a custom operator where `<` will actually be needed?
I have even stronger doubts on `=`.
Maybe we can even contract this feature to `parent(Comparative)` or
something without losing any expressivity?

3. Can we allow operators to have less priority than `=`?
If yes, can you give an example of such operator?

- Anton

2016-04-08 8:59 GMT+03:00 Chris Lattner <clattner@apple.com>:

On Apr 7, 2016, at 1:39 PM, Антон Жилин via swift-evolution < >> swift-evolution@swift.org> wrote:

First of all, sorry for the delay. I still hope to finish the discussion
and push the proposal to review for Swift 3.0.
Link for newcomers:

https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md

Sadly, I've moved into the territory opposite to what I had in mind in
the beginning: absense of conflict resolution.
I wanted lightweight directives, but am moving to closed precedence
groups.

It's just IMHO, and I think I just need input on this from more people. I
still have not heard anything from Core team.

Hi Антон,

I’m sorry for the delay, I have been out of town recently. I haven’t
read the upstream thread so I hope this isn’t too duplicative. Here is my
2c:

- I completely agree that numeric precedences are lame, it was always the
“plan” that they’d be removed someday, but that obviously still hasn’t
happened :-)
- I definitely agree that a partial ordering between precedences is all
that we need/want, and that unspecified relations should be an error.

That said, I feel like #operator is a major syntactic regression, both in
consistency and predictability. We use # for two things: directives (like
if) and for expressions (#file). The #operator is a declaration of an
operator, not an expression or a directive. For declarations, we
consistently use a keyword, which allows contextual modifiers before them,
along with a body (which is sometimes optional for certain kinds of
decls). I feel like you’re trying to syntactically reduce the weight of
something that doesn’t occur very often, which is no real win in
expressiveness, and harms consistency.

Likewise #precedence is a relationship between two operators. I’d
suggest putting them into the body of the operator declaration.

OTOH, the stuff inside the current operator declaration is a random
series of tokens with no apparent structure. I think it would be
reasonable to end up with something like:

infix operator <> {
  associativity: left
  precedenceLessThan: *
  precedenceEqualTo: -
}

Or whatever. The rationale here is that “infix” is primal on the
operator decl (and thus is outside the braces) but the rest of the stuff
can be omitted, so it goes inside.

Just in terms of the writing of the proposal, in the "Change precedence
mechanism” keep in mind that swift code generally doesn’t care about the
order of declarations (it doesn’t parse top down in the file like C does)
so the example is a bit misleading.

Question for you: have you considered introducing named precedence
groups, and having the relationships be between those groups? For example,
I could see something like:

operator group additive {}
operator group multiplicative { greaterThan: additive }
operator group exponential { greaterThan: additive }

Then:

infix operator + {
  associativity: left
  precedence: additive
}
infix operator - {
  associativity: left
  precedence: additive
}

etc.

-Chris

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

Right, `infix` operators without a precedence group logically should be
able to be used, just with parentheses everywhere.

But users will most likely want to use such operators with `=` without
parentheses. It means, such operators should still belong to some
precedence groups.

I suggest that for each such operator, an separate unnamed group should be
created. It will have no associativity and precedence greater than Ternary
(I actually agree this is the right choice).

I also think it is OK that other operators will not be able to specify
precedence relation with such "unprecedented" operators.

- Anton

8 Apr 2016, Ross O'Brien wrote:

···

If I want to define a new operator, it seems like an unnecessary overhead
to have to immediately decide which precedence group it should belong to
before it can be used (assuming it doesn't interact with other operators).
At the moment, new operators are implicitly assigned a 'default' precedence
of 100; can we make it so that new operators are implicitly assigned to a
'default' group with an effective precedence of 100? (I believe this is
currently the precedence of Ternary, but I'm not sure if I'd have Ternary
be the default group).

On Fri, Apr 8, 2016 at 5:59 PM, Антон Жилин <swift-evolution@swift.org > <javascript:_e(%7B%7D,'cvml','swift-evolution@swift.org');>> wrote:

Thank you for your reply, Chris!
I was thinking about purging directives from the proposal, and that was
what I needed to do it.
So, the proposal is now completely overhauled:

https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md

Yes, Maximilian and I have considered operator/precedence groups and they
have now moved from alternatives to main part of the proposal.

Questions:
1. Is it OK that associativity is moved to precedence groups and that
every operator must belong to a precedence group?
2. Dictionary-like or "functional keywords"? That is, `associativity:
left` or `associativity(left)`? So far, only second form has been used
somewhere inside declarations.
3. First-lower or first-upper? `additive` or `Additive`?
4. Empty body or no body? `prefix operator ! { }` or `prefix operator !`?

Just in case, some questions/concerns copied from previous discussion:

1. All precedence groups have a "parent".
It means, all operators will want to have precedence higher than
Comparative or Ternary, or, at least, Assignment.

2. Moreover, I could not find any case where I had to write anything
other than precedence(>, ...)
Of cause, I cheated, because I can control all these declarations.
Mere people will have to use `<` to say that Additive, for example,
should have less priority than their custom operator.

But... can you build a custom operator where `<` will actually be needed?
I have even stronger doubts on `=`.
Maybe we can even contract this feature to `parent(Comparative)` or
something without losing any expressivity?

3. Can we allow operators to have less priority than `=`?
If yes, can you give an example of such operator?

- Anton

2016-04-08 8:59 GMT+03:00 Chris Lattner <clattner@apple.com
<javascript:_e(%7B%7D,'cvml','clattner@apple.com');>>:

On Apr 7, 2016, at 1:39 PM, Антон Жилин via swift-evolution < >>> swift-evolution@swift.org >>> <javascript:_e(%7B%7D,'cvml','swift-evolution@swift.org');>> wrote:

First of all, sorry for the delay. I still hope to finish the discussion
and push the proposal to review for Swift 3.0.
Link for newcomers:

https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md

Sadly, I've moved into the territory opposite to what I had in mind in
the beginning: absense of conflict resolution.
I wanted lightweight directives, but am moving to closed precedence
groups.

It's just IMHO, and I think I just need input on this from more people.
I still have not heard anything from Core team.

Hi Антон,

I’m sorry for the delay, I have been out of town recently. I haven’t
read the upstream thread so I hope this isn’t too duplicative. Here is my
2c:

- I completely agree that numeric precedences are lame, it was always
the “plan” that they’d be removed someday, but that obviously still hasn’t
happened :-)
- I definitely agree that a partial ordering between precedences is all
that we need/want, and that unspecified relations should be an error.

That said, I feel like #operator is a major syntactic regression, both
in consistency and predictability. We use # for two things: directives
(like if) and for expressions (#file). The #operator is a declaration of
an operator, not an expression or a directive. For declarations, we
consistently use a keyword, which allows contextual modifiers before them,
along with a body (which is sometimes optional for certain kinds of
decls). I feel like you’re trying to syntactically reduce the weight of
something that doesn’t occur very often, which is no real win in
expressiveness, and harms consistency.

Likewise #precedence is a relationship between two operators. I’d
suggest putting them into the body of the operator declaration.

OTOH, the stuff inside the current operator declaration is a random
series of tokens with no apparent structure. I think it would be
reasonable to end up with something like:

infix operator <> {
  associativity: left
  precedenceLessThan: *
  precedenceEqualTo: -
}

Or whatever. The rationale here is that “infix” is primal on the
operator decl (and thus is outside the braces) but the rest of the stuff
can be omitted, so it goes inside.

Just in terms of the writing of the proposal, in the "Change precedence
mechanism” keep in mind that swift code generally doesn’t care about the
order of declarations (it doesn’t parse top down in the file like C does)
so the example is a bit misleading.

Question for you: have you considered introducing named precedence
groups, and having the relationships be between those groups? For example,
I could see something like:

operator group additive {}
operator group multiplicative { greaterThan: additive }
operator group exponential { greaterThan: additive }

Then:

infix operator + {
  associativity: left
  precedence: additive
}
infix operator - {
  associativity: left
  precedence: additive
}

etc.

-Chris

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
<javascript:_e(%7B%7D,'cvml','swift-evolution@swift.org');>
https://lists.swift.org/mailman/listinfo/swift-evolution

The question 4 (`prefix operator ! { }` or `prefix operator !`) seems dead
simple, because if we need to declare precedence group in body of infix
operators, then other operators should have it for consistency.

It's not.
I suggest an alternative syntax for that:
infix operator <> : Comparative

Colon immediately after the operator may not look the best, but it's the
only disadvantage I can find. It looks like inheritance and has similar
meaning.
So, in this scheme, all operators will have no body.

I also described two methods to declare that operator belongs to a
precedence group: in `members` and in operator declaration.
I suggest that this new syntax looks brief/natural enough to remove
`members` option entirely. "There should be one - and preferably only one -
obvious way to do it."

- Anton

···

2016-04-08 19:59 GMT+03:00 Антон Жилин <antonyzhilin@gmail.com>:

Thank you for your reply, Chris!
I was thinking about purging directives from the proposal, and that was
what I needed to do it.
So, the proposal is now completely overhauled:

https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md

Yes, Maximilian and I have considered operator/precedence groups and they
have now moved from alternatives to main part of the proposal.

Questions:
1. Is it OK that associativity is moved to precedence groups and that
every operator must belong to a precedence group?
2. Dictionary-like or "functional keywords"? That is, `associativity:
left` or `associativity(left)`? So far, only second form has been used
somewhere inside declarations.
3. First-lower or first-upper? `additive` or `Additive`?
4. Empty body or no body? `prefix operator ! { }` or `prefix operator !`?

Just in case, some questions/concerns copied from previous discussion:

1. All precedence groups have a "parent".
It means, all operators will want to have precedence higher than
Comparative or Ternary, or, at least, Assignment.

2. Moreover, I could not find any case where I had to write anything other
than precedence(>, ...)
Of cause, I cheated, because I can control all these declarations.
Mere people will have to use `<` to say that Additive, for example, should
have less priority than their custom operator.

But... can you build a custom operator where `<` will actually be needed?
I have even stronger doubts on `=`.
Maybe we can even contract this feature to `parent(Comparative)` or
something without losing any expressivity?

3. Can we allow operators to have less priority than `=`?
If yes, can you give an example of such operator?

- Anton

2016-04-08 8:59 GMT+03:00 Chris Lattner <clattner@apple.com>:

On Apr 7, 2016, at 1:39 PM, Антон Жилин via swift-evolution < >> swift-evolution@swift.org> wrote:

First of all, sorry for the delay. I still hope to finish the discussion
and push the proposal to review for Swift 3.0.
Link for newcomers:

https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md

Sadly, I've moved into the territory opposite to what I had in mind in
the beginning: absense of conflict resolution.
I wanted lightweight directives, but am moving to closed precedence
groups.

It's just IMHO, and I think I just need input on this from more people. I
still have not heard anything from Core team.

Hi Антон,

I’m sorry for the delay, I have been out of town recently. I haven’t
read the upstream thread so I hope this isn’t too duplicative. Here is my
2c:

- I completely agree that numeric precedences are lame, it was always the
“plan” that they’d be removed someday, but that obviously still hasn’t
happened :-)
- I definitely agree that a partial ordering between precedences is all
that we need/want, and that unspecified relations should be an error.

That said, I feel like #operator is a major syntactic regression, both in
consistency and predictability. We use # for two things: directives (like
if) and for expressions (#file). The #operator is a declaration of an
operator, not an expression or a directive. For declarations, we
consistently use a keyword, which allows contextual modifiers before them,
along with a body (which is sometimes optional for certain kinds of
decls). I feel like you’re trying to syntactically reduce the weight of
something that doesn’t occur very often, which is no real win in
expressiveness, and harms consistency.

Likewise #precedence is a relationship between two operators. I’d
suggest putting them into the body of the operator declaration.

OTOH, the stuff inside the current operator declaration is a random
series of tokens with no apparent structure. I think it would be
reasonable to end up with something like:

infix operator <> {
  associativity: left
  precedenceLessThan: *
  precedenceEqualTo: -
}

Or whatever. The rationale here is that “infix” is primal on the
operator decl (and thus is outside the braces) but the rest of the stuff
can be omitted, so it goes inside.

Just in terms of the writing of the proposal, in the "Change precedence
mechanism” keep in mind that swift code generally doesn’t care about the
order of declarations (it doesn’t parse top down in the file like C does)
so the example is a bit misleading.

Question for you: have you considered introducing named precedence
groups, and having the relationships be between those groups? For example,
I could see something like:

operator group additive {}
operator group multiplicative { greaterThan: additive }
operator group exponential { greaterThan: additive }

Then:

infix operator + {
  associativity: left
  precedence: additive
}
infix operator - {
  associativity: left
  precedence: additive
}

etc.

-Chris

- I definitely agree that a partial ordering between precedences is all that we need/want, and that unspecified relations should be an error.
...
Question for you: have you considered introducing named precedence groups, and having the relationships be between those groups? For example, I could see something like:

  operator group additive {}
  operator group multiplicative { greaterThan: additive }
  operator group exponential { greaterThan: additive }

Also +10, would be interested in your opinion about:

1) disallowing adding new operator groups outside the stdlib;

I don’t see why we would do that. This would lead us directly into the world of C++ operator overloading, where everyone reuses existing operators instead of defining their new and unique operators. IMO it is much better to "know that you don’t know” what a symbol is, rather than assuming it has the obvious semantics and being surprised because it was overloaded.

2) disallowing adding operators to uncommon groups like subscripting,
function calls, etc.

Subscripting and function calls are not operators.

-Chris

···

On Apr 8, 2016, at 5:16 AM, Rainer Brockerhoff via swift-evolution <swift-evolution@swift.org> wrote:

Based on commit ‘01317e1a’:

I think that it makes sense for membership to live outside of a precedence group. An example is if I wanted to add a new assignment operator ( maybe ??= 'assign if nil’), I would want it to have the same precedence as existing assignment operators, including precedence with other custom operators.

Secondly, I think the relationships between precedence groups should be defined outside of an existing precedence group. If I have two libraries that declare operators in their own custom groups, I may need to define a relationship between those groups.

This leads the group declaration itself being just of a name and associativity.

If group precedence is declared externally, there isn’t a need to support ‘>’. Since we are declaring a relationship and not evaluating a relationship, there are side-effects that developers will need to understand if they are trying to comprehend precedence groups in aggregate. Having the groups appear consistently in the same order when defining precedence may help with this.

I still assume these relationships are meant to be constrained to a DAG, although there might be cases where cycles (or even having multiple graphs) would still be unambiguous. I can’t wrap my head around implementation to the point of understanding evaluation if not a DAG yet, nor practical reasons to have cycles in relations.

Two groups may be unable to be declared to be equivalent. First, they need to be of the same associativity. Second are also possibilities of graph cycles once the relationships of both groups are overlaid. This is actually the trouble I alluded to in my first email in the thread.

Finally, an infix operator is part of one and only one group. It might make sense to have a default group (with no associativity) for operators to fall into if they do not declare a precedence group.

Oh wait, Yet another quasi-syntax based on the above:

precedencegroup Additive, associativity: left
precedencerelation Additive < Multiplicative
precedencerelation Range < Additive

infix operator +, group: Additive

-DW

···

On Apr 8, 2016, at 1:28 PM, Антон Жилин via swift-evolution <swift-evolution@swift.org> wrote:

The question 4 (`prefix operator ! { }` or `prefix operator !`) seems dead simple, because if we need to declare precedence group in body of infix operators, then other operators should have it for consistency.

It's not.
I suggest an alternative syntax for that:
infix operator <> : Comparative

Colon immediately after the operator may not look the best, but it's the only disadvantage I can find. It looks like inheritance and has similar meaning.
So, in this scheme, all operators will have no body.

I also described two methods to declare that operator belongs to a precedence group: in `members` and in operator declaration.
I suggest that this new syntax looks brief/natural enough to remove `members` option entirely. "There should be one - and preferably only one - obvious way to do it."

- Anton

2016-04-08 19:59 GMT+03:00 Антон Жилин <antonyzhilin@gmail.com <mailto:antonyzhilin@gmail.com>>:
Thank you for your reply, Chris!
I was thinking about purging directives from the proposal, and that was what I needed to do it.
So, the proposal is now completely overhauled:
https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md

Yes, Maximilian and I have considered operator/precedence groups and they have now moved from alternatives to main part of the proposal.

Questions:
1. Is it OK that associativity is moved to precedence groups and that every operator must belong to a precedence group?
2. Dictionary-like or "functional keywords"? That is, `associativity: left` or `associativity(left)`? So far, only second form has been used somewhere inside declarations.
3. First-lower or first-upper? `additive` or `Additive`?
4. Empty body or no body? `prefix operator ! { }` or `prefix operator !`?

Just in case, some questions/concerns copied from previous discussion:

1. All precedence groups have a "parent".
It means, all operators will want to have precedence higher than Comparative or Ternary, or, at least, Assignment.

2. Moreover, I could not find any case where I had to write anything other than precedence(>, ...)
Of cause, I cheated, because I can control all these declarations.
Mere people will have to use `<` to say that Additive, for example, should have less priority than their custom operator.

But... can you build a custom operator where `<` will actually be needed? I have even stronger doubts on `=`.
Maybe we can even contract this feature to `parent(Comparative)` or something without losing any expressivity?

3. Can we allow operators to have less priority than `=`?
If yes, can you give an example of such operator?

- Anton

2016-04-08 8:59 GMT+03:00 Chris Lattner <clattner@apple.com <mailto:clattner@apple.com>>:

On Apr 7, 2016, at 1:39 PM, Антон Жилин via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

First of all, sorry for the delay. I still hope to finish the discussion and push the proposal to review for Swift 3.0.
Link for newcomers:
https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md

Sadly, I've moved into the territory opposite to what I had in mind in the beginning: absense of conflict resolution.
I wanted lightweight directives, but am moving to closed precedence groups.

It's just IMHO, and I think I just need input on this from more people. I still have not heard anything from Core team.

Hi Антон,

I’m sorry for the delay, I have been out of town recently. I haven’t read the upstream thread so I hope this isn’t too duplicative. Here is my 2c:

- I completely agree that numeric precedences are lame, it was always the “plan” that they’d be removed someday, but that obviously still hasn’t happened :-)
- I definitely agree that a partial ordering between precedences is all that we need/want, and that unspecified relations should be an error.

That said, I feel like #operator is a major syntactic regression, both in consistency and predictability. We use # for two things: directives (like if) and for expressions (#file). The #operator is a declaration of an operator, not an expression or a directive. For declarations, we consistently use a keyword, which allows contextual modifiers before them, along with a body (which is sometimes optional for certain kinds of decls). I feel like you’re trying to syntactically reduce the weight of something that doesn’t occur very often, which is no real win in expressiveness, and harms consistency.

Likewise #precedence is a relationship between two operators. I’d suggest putting them into the body of the operator declaration.

OTOH, the stuff inside the current operator declaration is a random series of tokens with no apparent structure. I think it would be reasonable to end up with something like:

infix operator <> {
  associativity: left
  precedenceLessThan: *
  precedenceEqualTo: -
}

Or whatever. The rationale here is that “infix” is primal on the operator decl (and thus is outside the braces) but the rest of the stuff can be omitted, so it goes inside.

Just in terms of the writing of the proposal, in the "Change precedence mechanism” keep in mind that swift code generally doesn’t care about the order of declarations (it doesn’t parse top down in the file like C does) so the example is a bit misleading.

Question for you: have you considered introducing named precedence groups, and having the relationships be between those groups? For example, I could see something like:

  operator group additive {}
  operator group multiplicative { greaterThan: additive }
  operator group exponential { greaterThan: additive }

Then:

infix operator + {
  associativity: left
  precedence: additive
}
infix operator - {
  associativity: left
  precedence: additive
}

etc.

-Chris

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

Right, I agree. I consider it to be the "safe default" for an operator to be non-associative and unordered with respect to all other operators. This would require using parentheses to disambiguate, which seems safer than a default precedence level. This proposal also eliminates the notion of a strictly ordered set of precedences.

I do think it is useful to be able to specify precedence relationships without having to define a “group”, to avoid boilerplate when you have one operator at a logical level (“??” for example).

-Chris

···

On Apr 8, 2016, at 10:46 AM, Антон Жилин via swift-evolution <swift-evolution@swift.org> wrote:

Right, `infix` operators without a precedence group logically should be able to be used, just with parentheses everywhere.

But users will most likely want to use such operators with `=` without parentheses. It means, such operators should still belong to some precedence groups.

I suggest that for each such operator, an separate unnamed group should be created. It will have no associativity and precedence greater than Ternary (I actually agree this is the right choice).

I also think it is OK that other operators will not be able to specify precedence relation with such "unprecedented" operators

I agree, this is an nice approach. You’re basically saying that the <> operator is a member of the set of Comparative operators, thereby “inheriting” its precedence behaviors.

-Chris

···

On Apr 8, 2016, at 12:28 PM, Антон Жилин <antonyzhilin@gmail.com> wrote:

The question 4 (`prefix operator ! { }` or `prefix operator !`) seems dead simple, because if we need to declare precedence group in body of infix operators, then other operators should have it for consistency.

It's not.
I suggest an alternative syntax for that:
infix operator <> : Comparative

Colon immediately after the operator may not look the best, but it's the only disadvantage I can find. It looks like inheritance and has similar meaning.

Chris, thanks for commenting, but see below:

- I definitely agree that a partial ordering between precedences is all that we need/want, and that unspecified relations should be an error.
...
Question for you: have you considered introducing named precedence groups, and having the relationships be between those groups? For example, I could see something like:

  operator group additive {}
  operator group multiplicative { greaterThan: additive }
  operator group exponential { greaterThan: additive }

Also +10, would be interested in your opinion about:

1) disallowing adding new operator groups outside the stdlib;

I don’t see why we would do that. This would lead us directly into
the world of C++ operator overloading, where everyone reuses existing
operators instead of defining their new and unique operators. IMO it
is much better to "know that you don’t know” what a symbol is, rather
than assuming it has the obvious semantics and being surprised
because it was overloaded.

I agree with you a 100% regarding new operators, but notice I said
"adding new operator GROUPS". I don't see much sense in adding a new
precedence group beyond the ones already defined.

This goes along with your comment later in this thread:

...This would require using parentheses to disambiguate...

which I always do — I never remember most of the precedences.

2) disallowing adding operators to uncommon groups like subscripting,
function calls, etc.

Subscripting and function calls are not operators.

Oops, right. I meant in the context of "expressions", as used in the
Swift book.

···

On 4/9/16 10:33, Chris Lattner via swift-evolution wrote:

On Apr 8, 2016, at 5:16 AM, Rainer Brockerhoff via swift-evolution <swift-evolution@swift.org> wrote:

--
Rainer Brockerhoff <rainer@brockerhoff.net>
Belo Horizonte, Brazil
"In the affairs of others even fools are wise
In their own business even sages err."

Inline:

Based on commit ‘01317e1a’:

I think that it makes sense for membership to live outside of a precedence
group. An example is if I wanted to add a new assignment operator ( maybe
??= 'assign if nil’), I would want it to have the same precedence as
existing assignment operators, including precedence with other custom
operators.

Right, the proposal currently allows defining membership both inside and
outside the precedence group, but I agree that with terse enough syntax,
"outside only" will suffice.

Secondly, I think the relationships between precedence groups should be

defined outside of an existing precedence group. If I have two libraries
that declare operators in their own custom groups, I may need to define a
relationship between those groups.

This is a highly discussable question. "Outside" option makes it easy to
merge standard library operators into a single hierarchy again. Maybe this
question can be formulated as follows: should module creator have total
control over its operators, or can their behaviour be modified by user?

This leads the group declaration itself being just of a name and
associativity.

If group precedence is declared externally, there isn’t a need to support
‘>’. Since we are declaring a relationship and not evaluating a
relationship, there are side-effects that developers will need to
understand if they are trying to comprehend precedence groups in aggregate.
Having the groups appear consistently in the same order when defining
precedence may help with this.

I don't think supporting `>` puts much burden on grammar and consistency,
but yeah, it gets some points for external precedence.

I still assume these relationships are meant to be constrained to a DAG,
although there might be cases where cycles (or even having multiple graphs)
would still be unambiguous. I can’t wrap my head around implementation to
the point of understanding evaluation if not a DAG yet, nor practical
reasons to have cycles in relations.

Two groups may be unable to be declared to be equivalent. First, they need
to be of the same associativity. Second are also possibilities of graph
cycles once the relationships of both groups are overlaid. This is actually
the trouble I alluded to in my first email in the thread.

This time the proposal actually reflects these ideas.

Finally, an infix operator is part of one and only one group. It might make

sense to have a default group (with no associativity) for operators to fall
into if they do not declare a precedence group.

I have written about creating a separate unnamed group for each operator.
That is nonsense, of course, that should be a single named group without
associativity.

Oh wait, Yet another quasi-syntax based on the above:

precedencegroup Additive, associativity: left
precedencerelation Additive < Multiplicative
precedencerelation Range < Additive
infix operator +, group: Additive

I actually like this syntax (the absence of body, especially), but that
commas are inconsistent with the rest of the language. My take at it (hope
somebody can do better):

precedencegroup Additive : associativity(left)
precedencerelation Additive < Multiplicative
precedencerelation Range < Additive
infix operator + : Additive

···

2016-04-09 0:17 GMT+03:00 David Waite <david@alkaline-solutions.com>:

-DW

On Apr 8, 2016, at 1:28 PM, Антон Жилин via swift-evolution < > swift-evolution@swift.org> wrote:

The question 4 (`prefix operator ! { }` or `prefix operator !`) seems
dead simple, because if we need to declare precedence group in body of
infix operators, then other operators should have it for consistency.

It's not.
I suggest an alternative syntax for that:
infix operator <> : Comparative

Colon immediately after the operator may not look the best, but it's the
only disadvantage I can find. It looks like inheritance and has similar
meaning.
So, in this scheme, all operators will have no body.

I also described two methods to declare that operator belongs to a
precedence group: in `members` and in operator declaration.
I suggest that this new syntax looks brief/natural enough to remove
`members` option entirely. "There should be one - and preferably only one -
obvious way to do it."

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

Thought there is the obvious counterpoint: sugaring this one case doesn’t seem worthwhile, given how infrequently operators are defined. It is quite reasonable to start simple and always require an operator to be a member of a group. We could eliminate that boilerplate at some point down the road if it is an issue in practice.

-Chris

···

On Apr 9, 2016, at 6:36 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:
I do think it is useful to be able to specify precedence relationships without having to define a “group”, to avoid boilerplate when you have one operator at a logical level (“??” for example).

As always, link to the proposal:
https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md

Without further ado, I changed syntax for declaring that an operator
belongs to a group. It now looks like:
infix operator <> : Comparative

Next, I added a notion of default precedence group for infix operators:
https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md#default-precedence-group

Next, I added a notion of special operatrors that will allow nice
declarations in the Standard Library:
https://github.com/Anton3/swift-evolution/blob/operator-precedence/proposals/NNNN-operator-precedence.md#special-operators

I have a question on this: is that right? Because corresponding operator
functions still won't be declared anywhere.

Now, I see only 1 large question/problem risen by David Waite:
Should precedence relationships be defined inside or outside of precedence
groups?
That is: should we be able to add arbitrary relationships between existing
groups?

If we discuss this and no more problems are discovered, then I think, we
will be ready for review.

···

2016-04-09 16:40 GMT+03:00 Chris Lattner <clattner@apple.com>:

> On Apr 9, 2016, at 6:36 AM, Chris Lattner via swift-evolution < > swift-evolution@swift.org> wrote:
> I do think it is useful to be able to specify precedence relationships
without having to define a “group”, to avoid boilerplate when you have one
operator at a logical level (“??” for example).

Thought there is the obvious counterpoint: sugaring this one case doesn’t
seem worthwhile, given how infrequently operators are defined. It is quite
reasonable to start simple and always require an operator to be a member of
a group. We could eliminate that boilerplate at some point down the road
if it is an issue in practice.

-Chris