> On May 18, 2016, at 4:06 PM, Tony Allevato <[email protected]> wrote:
>
> On Wed, May 18, 2016 at 1:56 PM Matthew Johnson via swift-evolution
> <[email protected] <mailto:[email protected]>> wrote:
>
> Personally, I find Rust’s approach a bit ugly. And Tony makes a very good
> point in the proposal that using words requires us to learn the word
> associated with each operator.
>
> Right—and in addition to the cognitive overload of knowing (and remembering)
> the word associated with each operator, it introduced bloat in those
> interfaces. End users of such an interface may question why there is a named
> method for that operator, and whether the named method and the operator
> function differently.
>
> Likewise, in many cases (such as arithmetic operations), it seems contrived
> to come up with names for an operator where that operator is already a term
> of art that can express the idea better than the words can.
>
>
> I noted some concerns about this proposal not including automatic
> trampolines. However, if we are not going to be able to make a breaking
> change like this in the standard library after Swift 3 I do think it is
> important to give this proposal significant consideration even without them.
> Automatic trampolines can be added later but we may not have the opportunity
> to fix the standard library protocols later.
>
> I wish I had been able to keep automatic trampolines in—I thought it was the
> "killer feature" that brings the whole proposal together. (Hey core team, you
> can still change your mind! :)
>
> That being said, I feel that the named-method approach is a huge step in the
> wrong direction and this proposal is strong enough without them to improve
> other existing ones, such as FloatingPoint, and would go a long way toward
> cleaning up the language in other extremely common cases (like anything that
> conforms to Equatable).
Tony (and core team), do you have any thoughts on the specific concerns I
brought up?
Imagine this:
protocol P {
static func ++++(lhs: Self, rhs: Self) -> Self
}
func ++++ <T: P>(lhs: T, rhs: T) -> T {
return T.++++(lhs, rhs)
}
protocol Q {
static func ++++(lhs: Self, rhs: Self) -> Self
}
func ++++ <T: Q>(lhs: T, rhs: T) -> T {
return T.++++(lhs, rhs)
}
struct S: P, Q {
static func ++++(lhs: Self, rhs: Self) -> Self {
// ...
}
}
let s1 = S()
let s2 = S()
let s3 = s1 ++++ s2 // compiler error, both trampolines are an equally good
match, resulting in ambiguity
// we have to add the following to resolve the ambiguity:
func ++++(lhs: S, rhs: S) -> S {
return S.++++(lhs, rhs)
}
You could argue that this is a contrived example and is unlikely to happen in
real code. My point is partly that it’s a regression from current state and
partly that it is very likely to be confusing if people run into it.
>
>
>
>
>>
>>
>>
>>
>>
>>
>>
>> 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.
>>
>> (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
>> [email protected] <mailto:[email protected]>
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>
>>
>> _______________________________________________
>> swift-evolution mailing list
>> [email protected] <mailto:[email protected]>
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>
>>
>> _______________________________________________
>> swift-evolution mailing list
>> [email protected] <mailto:[email protected]>
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>
> _______________________________________________
> swift-evolution mailing list
> [email protected] <mailto:[email protected]>
> https://lists.swift.org/mailman/listinfo/swift-evolution
> <https://lists.swift.org/mailman/listinfo/swift-evolution>
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution