[swift-evolution] [Review] SE-0091: Improving operator requirements in protocols

Nicola Salmoria nicola.salmoria at gmail.com
Wed May 18 15:14:06 CDT 2016


On Wed, May 18, 2016 at 10:03 PM, Matthew Johnson <matthew at anandabits.com>
wrote:

>
> On May 18, 2016, at 3:00 PM, Nicola Salmoria via swift-evolution <
> swift-evolution at swift.org> wrote:
>
>
>
> On Wed, May 18, 2016 at 8:03 PM, Tony Allevato <allevato at google.com>
> wrote:
>
>> On Wed, May 18, 2016 at 10:02 AM Nicola Salmoria via swift-evolution <
>> swift-evolution at swift.org> wrote:
>>
>>> > * What is your evaluation of the proposal?
>>>
>>> I'm generally in strong support, having long been a proponent of removing
>>> operators from protocols (the first occurrence was in this thread:
>>> http://article.gmane.org/gmane.comp.lang.swift.evolution/7935)
>>>
>>> I have several comments about the details of the proposal, however.
>>>
>>> 1) At the beginning, in the "Proposed solution" section, the proposal
>>> says
>>> "This document does not propose that the current way of defining
>>> operators
>>> be removed or changed at this time. Rather, we describe an addition that
>>> specifically provides improvements for protocol operator requirements."
>>>
>>> Later, however, there is a "Deprecation of non-static protocol operators"
>>> section which suggest to do exactly that, and this is reiterated in the
>>> "Impact on existing code" section.
>>>
>>> Since I think that the deprecation of global operator overloads is the
>>> crucial point of the proposal, I assume that the former is an oversight.
>>>
>>
>> I could probably do a better job of clarifying the wording here. The
>> proposal does *not* deprecate *all* global operator overloads. Global
>> operators can still be implemented as they have been in Swift. So if you
>> have a concrete type like `struct Matrix`, you can still define at the
>> global level `func +(lhs: Matrix, rhs: Matrix) -> Matrix`.
>>
>> What's being deprecated is the current syntax used to define operator
>> requirements inside protocols (by making the functions static) and the
>> manner by which subtypes conform (ditto, through static methods instead of
>> global functions).
>>
>
> OK, I guess the unclear part is when you talk about "an addition that
> specifically provides improvements for protocol operator requirements."
> This is not just an addition; it's intended to completely replace the
> protocol operator syntax.
>
>>
>>
>>> 2) The method signatures in the examples are not up to date with the
>>> current
>>> Swift 3 syntax. For example:
>>>
>>> protocol Equatable {
>>>   static func ==(lhs: Self, rhs: Self) -> Bool
>>> }
>>>
>>> should be:
>>>
>>> protocol Equatable {
>>>   static func ==(_ lhs: Self, _ rhs: Self) -> Bool
>>> }
>>>
>>
>> Unless I'm mistaken, from looking at the Swift 3 branch of stdlib, the
>> syntax changes don't appear to apply to operator functions. Since they are
>> a special case that don't have argument labels, it wouldn't make sense to
>> require them (or rather, the placeholders) here.
>>
>
> I don't agree with this.
>
> Operators are called like this:
>
> x = y + z
>
> Of course it doesn't make sense to have parameter labels there.
>
> But the ones inside the protocol are not operators. They are methods, and
> are called like methods. They happen to have funny names, but they are
> still methods, and are called like this:
>
> x = T.+(y, z)
>
> In this case not only it makes sense for the parameters to have labels,
> but making them behave differently from normal methods would be
> inconsistent, and a step backwards from all the progress that has been made
> in Swift 3 on that front.
>
>
>>
>>
>>> 3) As has already been noted by many others, the suggested syntax for
>>> prefix/postfix operators is overcomplicated. The proposal is:
>>>
>>> // These are deprecated, of course, but used here just to serve as an
>>> // example.
>>> static prefix func ++(_ value: inout Self) -> Self
>>> static postfix func ++(_ value: inout Self) -> Self
>>>
>>> We don't need that. Since the 'operators' declared inside protocols are
>>> effectively just normal methods (apart from their names), we just need to
>>> name the parameters accordingly:
>>>
>>> static func ++(prefix value: inout Self) -> Self
>>> static func ++(postfix value: inout Self) -> Self
>>>
>>> 4) I don't agree with the request to limit to static methods for the
>>> operator implementations.
>>> I support this for symmetrical binary operators like +, but there are
>>> other
>>> operators like += that seem to work better with members. That is, the
>>> proposed declaration:
>>>
>>> static func +=(_ lhs: inout Self, _ rhs: Self)
>>>
>>> is more similar to the global += operator definition, but is less clear
>>> than:
>>>
>>> mutating func +=(_ rhs: Self)
>>>
>>> this is apparent also at the call site. With the proposed syntax, one
>>> would
>>> need to do:
>>>
>>> func +=<T: Foo>(_ lhs: inout T, _ rhs: T) {
>>>     T.+=(lhs, rhs)
>>> }
>>>
>>> while with a member function this would read more naturally as:
>>>
>>> func +=<T: Foo>(_ lhs: inout T, _ rhs: T) {
>>>     lhs.+=(rhs)
>>> }
>>>
>>
>> I considered this, but eventually settled on "everything is static" for
>> consistency. As you mention, there's a stronger argument to be made for
>> assignment operators to have "left hand side is the receiver" semantics
>> than there are for standard infix operators, but from a consistency point
>> of view (and ease of learning), I think having everything static and the
>> signatures of the static operators matching those of the global operators
>> is preferable.
>>
>
> I think this would better be left as a choice to the author of the
> protocol. There doesn't seem to be any technical reason to place this
> restriction.
>
>
> The problem with this is that people will make different choices.  This
> may result in boilerplate where a type has to provide both static *and*
> instance methods to conform to different protocols.  Better to avoid that
> possibility.
>

Do you have a specific example in mind?

I expect the stdlib to illustrate what idiomatic Swift is expected to be,
and people to follow suit for the standard operators.


> What benefit do you perceive in allowing operator instance methods?
>

The fact that operators like += are more naturally implemented as an
instance method than as a static method is already a clear benefit to me.

But in general, there aren't only the standard operators; people will
define custom operators and will have different needs depending on their
semantics. If there isn't a technical limitation, I don't see a reason to
add arbitrary restrictions.


>
>
>
>> (Which is also why, as I mentioned in a previous reply, I would be open
>> to dropping the prefix/postfix keyword and making it an argument label
>> instead, in both contexts.)
>>
>>
>>>
>>> 5) the proposal mentions the open question of ambiguities between the dot
>>> syntax to access methods and operators whose name starts with a dot.
>>> This seems to be a real issue: I don't think
>>>
>>> return T....(minimum, maximum)
>>>
>>> looks any good, even if the compiler was able to parse it.
>>>
>>> However, this just means that the methods used to implement operators
>>> with
>>> problematic names would need to use different names. Arguably, the only
>>> cases where one would really want to use methods with operator names is
>>> for
>>> arithmetical operators. Custom operators like ... are better expressed as
>>> methods with more significant names.
>>>
>>
>> If there is a strong case where an operator is better implemented as a
>> global operator and a named method, this proposal still allows that, since
>> it's not deprecating all global operator definitions. A protocol could
>> certainly have a requirement that is a named method, and provide a global
>> generic operator that calls it.
>>
>>
>>>
>>> 6) It seems somewhat arbitrary to restrict method names to match an
>>> operator, nor to put requirements on the function signature. I'd say
>>> there
>>> are two cases, either the compiler can handle a method name that uses
>>> special characters, or it can't. If it can't, matching an operator name
>>> won't help. If it can, why put limits? There could be other creative
>>> uses of
>>> such names, which we would be ruling out for no particular reason. This
>>> is
>>> something that seems better left to the author of the protocol.
>>>
>>
>> IMO, to reduce potential confusion, I would argue that a function whose
>> name is the same as a defined operator should conform to the requirements
>> (such as argument count) of that operator. It's certainly worth discussion,
>> though! With that being said, it may be easier on users to "rule something
>> out" now and open it up later if need be, rather than to leave it open for
>> people to use and decide it needs to be closed later.
>>
>
> This doesn't seem different to me from having multiple functions with the
> same name and different signature, which Swift allows without problems.
> Again, I think this is a choice that the author of the protocol should
> make, and there doesn't seem to be any technical reason to require
> otherwise.
>
>
>>
>>
>>> 7) Automatic generation of trampoline functions is out of scope so I'm
>>> not
>>> going to talk much about it, I only want to mention that it would make
>>> sense
>>> to consider making such a feature as general as possible, instead of
>>> focusing exclusively on operators.
>>>
>>> For example, think of the common mathematical functions like sin, cos,
>>> etc.
>>> It could make sense to give them the same treatment as operators,
>>> declaring
>>> them as part of the FloatingPoint protocol but preserving the global
>>> functions too.
>>> It might even make sense to be able to create trampolines not only from
>>> global space to a type, but also from one type to another type, or even
>>> for
>>> all methods of a type (e.g. when boxing a value inside another type).
>>>
>>> > * Is the problem being addressed significant enough to warrant a
>>> change to
>>> Swift?
>>>
>>> Absolutely. The handling of operators in protocols has been one of the
>>> worst
>>> pain points in my use of Swift.
>>>
>>> > * Does this proposal fit well with the feel and direction of Swift?
>>>
>>> Yes; it significantly increases clarity and consistency.
>>>
>>> > * If you have used other languages or libraries with a similar feature,
>>> how do you feel that this proposal compares to those?
>>>
>>> I only have experience with C++ operator overloading, which is much less
>>> advanced.
>>>
>>> > * How much effort did you put into your review? A glance, a quick
>>> reading,
>>> or an in-depth study?
>>>
>>> An in-depth study of the proposal, and I read all the relevant threads on
>>> the mailing list.
>>>
>>> --
>>> 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
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160518/9d33a0fe/attachment.html>


More information about the swift-evolution mailing list