[swift-evolution] [swift-evolution-announce] [Review] SE-0067: Enhanced Floating Point Protocols

Xiaodi Wu xiaodi.wu at gmail.com
Tue Apr 26 13:40:53 CDT 2016


Again, +1 to Tony's analysis. In the context of numerics in particular,
global functions and operators are very much "normal means," and if
anything instance methods are rather "convenience."
On Tue, Apr 26, 2016 at 13:36 Tony Allevato via swift-evolution <
swift-evolution at swift.org> wrote:

> On Tue, Apr 26, 2016 at 11:29 AM Nicola Salmoria <
> nicola.salmoria at gmail.com> wrote:
>
>> On Tue, Apr 26, 2016 at 8:10 PM, Thorsten Seitz <tseitz42 at icloud.com>
>> wrote:
>>
>>> See inline.
>>>
>>> Am 26.04.2016 um 19:36 schrieb Nicola Salmoria via swift-evolution <
>>> swift-evolution at swift.org>:
>>>
>>> On Tue, Apr 26, 2016 at 4:28 PM, Tony Allevato <allevato at google.com>
>>> wrote:
>>>
>>>> On Sun, Apr 24, 2016 at 2:57 AM Nicola Salmoria via swift-evolution <
>>>> swift-evolution at swift.org> wrote:
>>>>
>>>>> > > func isEqual(to other: Self) ->Bool
>>>>> > > func isLess(than other: Self) ->Bool
>>>>> > > func isLessThanOrEqual(to other: Self) ->Bool
>>>>> >
>>>>> > I'm still not sure why these are methods instead of operators.
>>>>>
>>>>> I think this is an *excellent* choice, and I hope it is the first step
>>>>> to completely removing operators from protocols.
>>>>>
>>>>> IMHO throwing operators into protocols is inconsistent and confusing.
>>>>> Having regular methods and a single generic version of the operator that
>>>>> calls down on the type’s methods is clearer and guarantees that generic
>>>>> code can avoid ambiguities by calling the methods directly, instead of
>>>>> having to rely only on heavily overloaded global operators.
>>>>>
>>>>
>>>> I personally disagree on this point. To me, a protocol describes a set
>>>> of requirements for a type to fulfill, which includes things other than
>>>> methods. Just as a protocol can define initializers, properties, and
>>>> associated types that a type must define in order to conform, it makes
>>>> sense that a protocol would also define which operators a conforming type
>>>> must support.
>>>>
>>>
>>> Well, I'm not sure about that. A protocol describes what a type can do,
>>> so it's debatable whether a global function is within this scope.
>>>
>>> Operators are magically special: you can declare them inside a protocol
>>> and require them to be available for conformance, even if they don't belong
>>> to the type. You can't do the same thing for normal global functions, yet
>>> conceptually global functions and operators are the same thing.
>>>
>>>
>>>> Introducing a mapping between names and operators poses a few problems:
>>>>
>>>> – IMO, they are overly verbose and add noise to the definition. This
>>>> makes the language look less clean (I'm getting visions of NSDecimalNumber).
>>>> – They expose two ways to accomplish the same thing (writing
>>>> `x.isEqual(to: y)` and `x == y`).
>>>>
>>>
>>> That is my concern with this approach as well.
>>>
>>>
>>>
>>> – Do certain operators automatically get mapped to method names with
>>>> appropriate signatures across all types, or does a conforming type still
>>>> have to provide that mapping by implementing the operators separately? If
>>>> it's the latter, that's extra work for the author of the type writing the
>>>> protocol. If it's the former, does it make sense to automatically push
>>>> these operators for all types? Should any type that has an `add` method
>>>> automatically get `+` as a synonym as well? That may not be desirable.
>>>>
>>>
>>> The difference at the protocol declaration is between:
>>>
>>> protocol Equatable {
>>>     func ==(lhs: Self, rhs: Self) -> Bool
>>> }
>>>
>>> and:
>>>
>>> protocol Equatable {
>>>     func isEqual(to other: Self) -> Bool
>>> }
>>>
>>> func ==<T: Equatable>(lhs: T, rhs: T) -> Bool {
>>>     return lhs.isEqual(to: rhs)
>>> }
>>>
>>> so the latter is a bit more verbose, but arguably clearer in intent, and
>>> not different from how you would define any generic global function using a
>>> protocol, or from how you can define protocol extensions with default
>>> implementations that take advantage of the protocol's core methods.
>>>
>>>
>>> The problem is that it is no longer clear whether to use the method or
>>> the operator to check for equality.
>>>
>>> Now if we had some access modifier to hide the isEqual method except for
>>> overwriting it and using it within the operator, maybe some variant of
>>> 'protected' (e.g. visible in implementors and the same file as the
>>> protocol) then that approach would be fine.
>>>
>>> -Thorsten
>>>
>>
>> Why would you want to do that?
>>
>> I see operators mostly as a convenience: a shortcut to express in a more
>> concise way something which should also be available through normal means.
>>
>
> Why is the operator not the "normal means"? Centuries of mathematics tell
> us that "2 + 2 == 4", not "2.adding(2).isEqual(to: 4)". We should make it
> easier and consistent for Swift authors to write code that conforms to
> existing terms (or in this case, symbols) of art, not introduce a
> completely new and arbitrary set of methods that (1) bloat public
> interfaces and (2) map to the same operators anyway.
>
>
> It could be argued that generic code might prefer, for clarity, to use
>> explicit methods instead of vague global operators.
>>
>> The approved but still unimplemented
>>
>> https://github.com/apple/swift-evolution/blob/master/proposals/0042-flatten-method-types.md
>> also applies here, since the isEqual member method could also be used as
>> a static method for increased symmetry and clarity, i.e. instead of
>>
>> _ = x.isEqual(to: y)
>>
>> one could do
>>
>> _ = Equatable.isEqual(x, to: y)
>>
>> this could be useful in case of ambiguities.
>>
>> Nicola
>>
>>
>>
>>>
>>>
>>>
>>> The difference for the conformance is between:
>>>
>>> extension Foo : Equatable { }
>>>
>>> func ==(lhs: Foo, rhs: Foo) -> Bool {
>>>     return <comparison>
>>> }
>>>
>>> and:
>>>
>>> extension Bar : Equatable {
>>>     func isEqual(to: Bar) -> Bool {
>>>         return <comparison>
>>>     }
>>> }
>>>
>>> the former way to define the conformance can be confusing to newbies.
>>> The latter is straightforward and consistent with the usual way to adopt a
>>> protocol.
>>>
>>> The == operator looks exactly the same at its use points, but the way
>>> how it's implemented is different.
>>> In the former case, it's many overloads of a global function, which can
>>> stress the compiler's type inference and doesn't offer an obvious way to
>>> disambiguate in case of ambiguities.
>>> In the latter case, there is only one generic definition of ==, which
>>> automatically applies to all types that conform to the protocol.
>>>
>>> Nicola
>>>
>>>
>>>> I'm very supportive of the floating-point protocol proposal in general,
>>>> but I feel the arithmetic and comparison operations should be exposed by
>>>> operators alone and not by methods, where there is a suitable operator that
>>>> has the intended meaning.
>>>>
>>>>
>>>>
>>>>>
>>>>>>>>>> Nicola
>>>>>
>>>>> _______________________________________________
>>>>> swift-evolution mailing list
>>>>> swift-evolution at swift.org
>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>
>>>>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>
>>> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160426/1531d0b8/attachment.html>


More information about the swift-evolution mailing list