Symmetrical operators


(Andrew Volodin) #1

Hi, list!

I’m thinking about proposal that would add a possibility to save some time on creating symmetrical binary operators.

The latest code example from my math lib:

    @inline(__always)
    public static func *(lhs: Angle, rhs: Float) -> Angle {
        return Angle(lhs.degrees * rhs)
    }
    
    @inline(__always)
    public static func *(lhs: Float, rhs: Angle) -> Angle {
        return Angle(rhs.degrees * lhs)
    }

The API of Angle doesn’t really matter here, what’s important is that I have to write another operator to make it symmetrical. Not so hard: 3 lines of code. It can even refer to original implementation, instead of duplicating the logic. But I think it would be nice to have something like symmetrical keyword, just like we have associativity and precedence.

I also bet that all operators should be asymmetrical by default.

Any thoughts?


(David Sweeris) #2

I fully support adding a “@commutative” attribute or something to let the compiler know that a function can be called with its arguments out of order, but I’m thoroughly against turning it on by default. Some operations, such as matrix multiplication, aren’t even defined if you swap the arguments.

- Dave Sweeris

···

On Nov 13, 2016, at 1:38 PM, Андрей Володин via swift-evolution <swift-evolution@swift.org> wrote:

Hi, list!

I’m thinking about proposal that would add a possibility to save some time on creating symmetrical binary operators.

The latest code example from my math lib:

    @inline(__always)
    public static func *(lhs: Angle, rhs: Float) -> Angle {
        return Angle(lhs.degrees * rhs)
    }
    
    @inline(__always)
    public static func *(lhs: Float, rhs: Angle) -> Angle {
        return Angle(rhs.degrees * lhs)
    }

The API of Angle doesn’t really matter here, what’s important is that I have to write another operator to make it symmetrical. Not so hard: 3 lines of code. It can even refer to original implementation, instead of duplicating the logic. But I think it would be nice to have something like symmetrical keyword, just like we have associativity and precedence.

I also bet that all operators should be asymmetrical by default.

Any thoughts?


(ark dan) #3

David, what about un-labeled parameters? If a function has 2 parameters of the same type, how does compiler know which ones's which?

···

On Nov 13, 2016, at 9:49 PM, David Sweeris via swift-evolution <swift-evolution@swift.org> wrote:

On Nov 13, 2016, at 1:38 PM, Андрей Володин via swift-evolution <swift-evolution@swift.org> wrote:

Hi, list!

I’m thinking about proposal that would add a possibility to save some time on creating symmetrical binary operators.

The latest code example from my math lib:

    @inline(__always)
    public static func *(lhs: Angle, rhs: Float) -> Angle {
        return Angle(lhs.degrees * rhs)
    }
    
    @inline(__always)
    public static func *(lhs: Float, rhs: Angle) -> Angle {
        return Angle(rhs.degrees * lhs)
    }

The API of Angle doesn’t really matter here, what’s important is that I have to write another operator to make it symmetrical. Not so hard: 3 lines of code. It can even refer to original implementation, instead of duplicating the logic. But I think it would be nice to have something like symmetrical keyword, just like we have associativity and precedence.

I also bet that all operators should be asymmetrical by default.

Any thoughts?

I fully support adding a “@commutative” attribute or something to let the compiler know that a function can be called with its arguments out of order, but I’m thoroughly against turning it on by default. Some operations, such as matrix multiplication, aren’t even defined if you swap the arguments.

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


(Anton Zhilin) #4

-1
Not worth adding syntactic sugar for a narrow use case. Plus it's an
additive feature.


(David Sweeris) #5

If a function has two unlabeled parameters of the same type, you can already swap their order at the call site.

- Dave Sweeris

···

On Nov 13, 2016, at 19:04, arkadi daniyelian <arkdan@icloud.com> wrote:

David, what about un-labeled parameters? If a function has 2 parameters of the same type, how does compiler know which ones's which?


(David Sweeris) #6

Although you are correct in that the compiler wouldn't be able to guarantee that both "versions" would give the same answer, but that's currently the case anyway.

···

Sent from my iPhone

On Nov 13, 2016, at 20:03, David Sweeris via swift-evolution <swift-evolution@swift.org> wrote:

On Nov 13, 2016, at 19:04, arkadi daniyelian <arkdan@icloud.com> wrote:

David, what about un-labeled parameters? If a function has 2 parameters of the same type, how does compiler know which ones's which?

If a function has two unlabeled parameters of the same type, you can already swap their order at the call site.

- Dave Sweeris

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


(Dimitri Racordon) #7

+1

I think the use cases are not that sparse actually.
I would also argue that it would be easier to understand the intent of the code with some sort of keyword than with a hard copy of each function.

···

On 14 Nov 2016, at 10:51, Anton Zhilin via swift-evolution <swift-evolution@swift.org> wrote:

-1
Not worth adding syntactic sugar for a narrow use case. Plus it's an additive feature.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


#8

Perhaps a more general solution would be a way to mark functions as
“rearrangeable”, meaning the arguments can appear in any order.

I also like Haravikk’s idea for “outfix” operators—there are certainly a
large number of bracket-type Unicode characters that could be useful in
such a role.

Nevin

···

On Mon, Nov 14, 2016 at 6:48 AM, Haravikk via swift-evolution < swift-evolution@swift.org> wrote:

I'm a +1 on the feature, though for simply handling symmetry it's not a
super critical issue.

I wonder though, when you start looking at symmetry is it worth looking at
other patterns? For example, could symmetrical operators be covered by a
broader multi-part operator definition?

I was thinking recently it would be convenient if I could define say a
3-dimensional point like so: <x, y, z>

In this case you're looking at a symmetric operator with two different
components (opening and closing angle brackets) with the ability to take
three arguments. Is there a way we could define and implement something
along these lines? If so it would be very flexible, and potential allow us
to unify all operators into a single format.

For example, you can thing of a prefix operator as being a leading symbol
plus one argument, while a postfix is one argument plus a trailing symbol,
a binary operator is an argument, a symbol and another argument, a
symmetric operator is a leading symbol, an argument and a trailing symbol
(doesn't have to be identical).

If we had a means of specifying operators in this way (as a complete
pattern) we could do away with special cases of operators entirely, though
they may be worth keeping for compatibility and as a shorthand.

> On 14 Nov 2016, at 09:57, Dimitri Racordon via swift-evolution < > swift-evolution@swift.org> wrote:
>
> +1
>
> I think the use cases are not that sparse actually.
> I would also argue that it would be easier to understand the intent of
the code with some sort of keyword than with a hard copy of each function.
>
>
>
>> On 14 Nov 2016, at 10:51, Anton Zhilin via swift-evolution < > swift-evolution@swift.org> wrote:
>>
>> -1
>> Not worth adding syntactic sugar for a narrow use case. Plus it's an
additive feature.
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

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


(Haravikk) #9

I'm a +1 on the feature, though for simply handling symmetry it's not a super critical issue.

I wonder though, when you start looking at symmetry is it worth looking at other patterns? For example, could symmetrical operators be covered by a broader multi-part operator definition?

I was thinking recently it would be convenient if I could define say a 3-dimensional point like so: <x, y, z>

In this case you're looking at a symmetric operator with two different components (opening and closing angle brackets) with the ability to take three arguments. Is there a way we could define and implement something along these lines? If so it would be very flexible, and potential allow us to unify all operators into a single format.

For example, you can thing of a prefix operator as being a leading symbol plus one argument, while a postfix is one argument plus a trailing symbol, a binary operator is an argument, a symbol and another argument, a symmetric operator is a leading symbol, an argument and a trailing symbol (doesn't have to be identical).

If we had a means of specifying operators in this way (as a complete pattern) we could do away with special cases of operators entirely, though they may be worth keeping for compatibility and as a shorthand.

···

On 14 Nov 2016, at 09:57, Dimitri Racordon via swift-evolution <swift-evolution@swift.org> wrote:

+1

I think the use cases are not that sparse actually.
I would also argue that it would be easier to understand the intent of the code with some sort of keyword than with a hard copy of each function.

On 14 Nov 2016, at 10:51, Anton Zhilin via swift-evolution <swift-evolution@swift.org> wrote:

-1
Not worth adding syntactic sugar for a narrow use case. Plus it's an additive feature.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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


(David Sweeris) #10

+11

I would *love* to be able to specify "complex operators" that take more than two arguments, are “symmetric” (in Haravikk’s sense of the word, like "let y = |x|”), or really have whatever syntax I want. The difficulty would be doing it in such a way that it doesn't conflict with the existing grammar. This sounds difficult (to me, anyway), but it turns out that if we can represent operators’ grammar as regular expressions, it might be a more-or-less solved problem (http://stackoverflow.com/questions/3410256/regex-determine-if-two-regular-expressions-could-match-for-the-same-input). Now, actually finding a useful “complex” syntax that doesn’t conflict with anything might be tricky, but that’s not the language’s problem.

- Dave Sweeris

···

On Nov 14, 2016, at 5:48 AM, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

I'm a +1 on the feature, though for simply handling symmetry it's not a super critical issue.

I wonder though, when you start looking at symmetry is it worth looking at other patterns? For example, could symmetrical operators be covered by a broader multi-part operator definition?

I was thinking recently it would be convenient if I could define say a 3-dimensional point like so: <x, y, z>

In this case you're looking at a symmetric operator with two different components (opening and closing angle brackets) with the ability to take three arguments. Is there a way we could define and implement something along these lines? If so it would be very flexible, and potential allow us to unify all operators into a single format.

For example, you can thing of a prefix operator as being a leading symbol plus one argument, while a postfix is one argument plus a trailing symbol, a binary operator is an argument, a symbol and another argument, a symmetric operator is a leading symbol, an argument and a trailing symbol (doesn't have to be identical).

If we had a means of specifying operators in this way (as a complete pattern) we could do away with special cases of operators entirely, though they may be worth keeping for compatibility and as a shorthand.


(Andrew Volodin) #11

Отправлено с iPhone

···

14 нояб. 2016 г., в 12:51, Anton Zhilin <antonyzhilin@gmail.com> написал(а):

-1
Not worth adding syntactic sugar for a narrow use case. Plus it's an additive feature.


(Andrew Volodin) #12

Well, I dont actually think it can be considered as a syntax sugar. It requires creating separate function to achieve same effect. This is all about how operators behave in general.

···

14 нояб. 2016 г., в 12:51, Anton Zhilin <antonyzhilin@gmail.com> написал(а):

-1
Not worth adding syntactic sugar for a narrow use case. Plus it's an additive feature.


(Karl) #13

Commutative operators are very common and I would definitely +1 a shorthand for them.

You seem to be talking about a custom literal, rather than an operator - you said you want to “define” a point with some special syntax. Try ArrayLiteralConvertible.

- Karl

···

On 14 Nov 2016, at 12:48, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

I'm a +1 on the feature, though for simply handling symmetry it's not a super critical issue.

I wonder though, when you start looking at symmetry is it worth looking at other patterns? For example, could symmetrical operators be covered by a broader multi-part operator definition?

I was thinking recently it would be convenient if I could define say a 3-dimensional point like so: <x, y, z>

In this case you're looking at a symmetric operator with two different components (opening and closing angle brackets) with the ability to take three arguments. Is there a way we could define and implement something along these lines? If so it would be very flexible, and potential allow us to unify all operators into a single format.

For example, you can thing of a prefix operator as being a leading symbol plus one argument, while a postfix is one argument plus a trailing symbol, a binary operator is an argument, a symbol and another argument, a symmetric operator is a leading symbol, an argument and a trailing symbol (doesn't have to be identical).

If we had a means of specifying operators in this way (as a complete pattern) we could do away with special cases of operators entirely, though they may be worth keeping for compatibility and as a shorthand.

On 14 Nov 2016, at 09:57, Dimitri Racordon via swift-evolution <swift-evolution@swift.org> wrote:

+1

I think the use cases are not that sparse actually.
I would also argue that it would be easier to understand the intent of the code with some sort of keyword than with a hard copy of each function.

On 14 Nov 2016, at 10:51, Anton Zhilin via swift-evolution <swift-evolution@swift.org> wrote:

-1
Not worth adding syntactic sugar for a narrow use case. Plus it's an additive feature.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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

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


(David Sweeris) #14

The problem is there’s no way to conform to ArrayLiteralConvertible only when a certain # of elements are present, and the protocol requires the init function to not be failable. In this particular case you can fake it by only copying the first 3 values from the array and using 0 to fill in missing elements. It could be argued that filling in the 0s is “correct enough”, but throwing out extra elements is certainly bad. And you’re still in the (undesirable, IMHO) position of using run-time checks to account for what amounts to a syntax error that should be easy to catch at compile-time.

- Dave Sweeris

···

On Nov 16, 2016, at 9:25 AM, Karl via swift-evolution <swift-evolution@swift.org> wrote:

On 14 Nov 2016, at 12:48, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

I'm a +1 on the feature, though for simply handling symmetry it's not a super critical issue.

I wonder though, when you start looking at symmetry is it worth looking at other patterns? For example, could symmetrical operators be covered by a broader multi-part operator definition?

I was thinking recently it would be convenient if I could define say a 3-dimensional point like so: <x, y, z>

In this case you're looking at a symmetric operator with two different components (opening and closing angle brackets) with the ability to take three arguments. Is there a way we could define and implement something along these lines? If so it would be very flexible, and potential allow us to unify all operators into a single format.

For example, you can thing of a prefix operator as being a leading symbol plus one argument, while a postfix is one argument plus a trailing symbol, a binary operator is an argument, a symbol and another argument, a symmetric operator is a leading symbol, an argument and a trailing symbol (doesn't have to be identical).

If we had a means of specifying operators in this way (as a complete pattern) we could do away with special cases of operators entirely, though they may be worth keeping for compatibility and as a shorthand.

On 14 Nov 2016, at 09:57, Dimitri Racordon via swift-evolution <swift-evolution@swift.org> wrote:

+1

I think the use cases are not that sparse actually.
I would also argue that it would be easier to understand the intent of the code with some sort of keyword than with a hard copy of each function.

On 14 Nov 2016, at 10:51, Anton Zhilin via swift-evolution <swift-evolution@swift.org> wrote:

-1
Not worth adding syntactic sugar for a narrow use case. Plus it's an additive feature.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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

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

Commutative operators are very common and I would definitely +1 a shorthand for them.

You seem to be talking about a custom literal, rather than an operator - you said you want to “define” a point with some special syntax. Try ArrayLiteralConvertible.


(Stephen Canon) #15

You can make it a precondition that the array have the right number of elements; this is what the simd module types on Apple platforms do, for example:

  1> import simd
  2> let w = [1,2,3,4] as float3
  fatal error: float3 requires a three-element array

but you're still left with a run-time error rather than a syntax-error, which is definitely not ideal.

– Steve

···

On Nov 16, 2016, at 10:47 AM, David Sweeris via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Nov 16, 2016, at 9:25 AM, Karl via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On 14 Nov 2016, at 12:48, Haravikk via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I'm a +1 on the feature, though for simply handling symmetry it's not a super critical issue.

I wonder though, when you start looking at symmetry is it worth looking at other patterns? For example, could symmetrical operators be covered by a broader multi-part operator definition?

I was thinking recently it would be convenient if I could define say a 3-dimensional point like so: <x, y, z>

In this case you're looking at a symmetric operator with two different components (opening and closing angle brackets) with the ability to take three arguments. Is there a way we could define and implement something along these lines? If so it would be very flexible, and potential allow us to unify all operators into a single format.

For example, you can thing of a prefix operator as being a leading symbol plus one argument, while a postfix is one argument plus a trailing symbol, a binary operator is an argument, a symbol and another argument, a symmetric operator is a leading symbol, an argument and a trailing symbol (doesn't have to be identical).

If we had a means of specifying operators in this way (as a complete pattern) we could do away with special cases of operators entirely, though they may be worth keeping for compatibility and as a shorthand.

On 14 Nov 2016, at 09:57, Dimitri Racordon via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

+1

I think the use cases are not that sparse actually.
I would also argue that it would be easier to understand the intent of the code with some sort of keyword than with a hard copy of each function.

On 14 Nov 2016, at 10:51, Anton Zhilin via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

-1
Not worth adding syntactic sugar for a narrow use case. Plus it's an additive feature.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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

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

Commutative operators are very common and I would definitely +1 a shorthand for them.

You seem to be talking about a custom literal, rather than an operator - you said you want to “define” a point with some special syntax. Try ArrayLiteralConvertible.

The problem is there’s no way to conform to ArrayLiteralConvertible only when a certain # of elements are present, and the protocol requires the init function to not be failable. In this particular case you can fake it by only copying the first 3 values from the array and using 0 to fill in missing elements. It could be argued that filling in the 0s is “correct enough”, but throwing out extra elements is certainly bad. And you’re still in the (undesirable, IMHO) position of using run-time checks to account for what amounts to a syntax error that should be easy to catch at compile-time.


(David Sweeris) #16

Oh! Good idea! Dunno why I hadn't thought of that :slight_smile:

Should this "custom operator grammar/syntax" part of the discussion get its own thread, or is it sufficiently related to the OP's "symmetry" idea?

- Dave Sweeris, who is aware that his deep and abiding love of exploring all the rabbit trails is probably quite a lot stronger than most people's, and doesn't want to unduly inflict his ADD on the list.

···

On Nov 16, 2016, at 10:35, Stephen Canon <scanon@apple.com> wrote:

On Nov 16, 2016, at 10:47 AM, David Sweeris via swift-evolution <swift-evolution@swift.org> wrote:

On Nov 16, 2016, at 9:25 AM, Karl via swift-evolution <swift-evolution@swift.org> wrote:

On 14 Nov 2016, at 12:48, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

I'm a +1 on the feature, though for simply handling symmetry it's not a super critical issue.

I wonder though, when you start looking at symmetry is it worth looking at other patterns? For example, could symmetrical operators be covered by a broader multi-part operator definition?

I was thinking recently it would be convenient if I could define say a 3-dimensional point like so: <x, y, z>

In this case you're looking at a symmetric operator with two different components (opening and closing angle brackets) with the ability to take three arguments. Is there a way we could define and implement something along these lines? If so it would be very flexible, and potential allow us to unify all operators into a single format.

For example, you can thing of a prefix operator as being a leading symbol plus one argument, while a postfix is one argument plus a trailing symbol, a binary operator is an argument, a symbol and another argument, a symmetric operator is a leading symbol, an argument and a trailing symbol (doesn't have to be identical).

If we had a means of specifying operators in this way (as a complete pattern) we could do away with special cases of operators entirely, though they may be worth keeping for compatibility and as a shorthand.

On 14 Nov 2016, at 09:57, Dimitri Racordon via swift-evolution <swift-evolution@swift.org> wrote:

+1

I think the use cases are not that sparse actually.
I would also argue that it would be easier to understand the intent of the code with some sort of keyword than with a hard copy of each function.

On 14 Nov 2016, at 10:51, Anton Zhilin via swift-evolution <swift-evolution@swift.org> wrote:

-1
Not worth adding syntactic sugar for a narrow use case. Plus it's an additive feature.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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

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

Commutative operators are very common and I would definitely +1 a shorthand for them.

You seem to be talking about a custom literal, rather than an operator - you said you want to “define” a point with some special syntax. Try ArrayLiteralConvertible.

The problem is there’s no way to conform to ArrayLiteralConvertible only when a certain # of elements are present, and the protocol requires the init function to not be failable. In this particular case you can fake it by only copying the first 3 values from the array and using 0 to fill in missing elements. It could be argued that filling in the 0s is “correct enough”, but throwing out extra elements is certainly bad. And you’re still in the (undesirable, IMHO) position of using run-time checks to account for what amounts to a syntax error that should be easy to catch at compile-time.

You can make it a precondition that the array have the right number of elements; this is what the simd module types on Apple platforms do, for example:

  1> import simd
  2> let w = [1,2,3,4] as float3
  fatal error: float3 requires a three-element array

but you're still left with a run-time error rather than a syntax-error, which is definitely not ideal.