> On May 18, 2016, at 3:14 PM, Nicola Salmoria <[email protected]> > wrote: > > > > On Wed, May 18, 2016 at 10:03 PM, Matthew Johnson <[email protected] > <mailto:[email protected]>> wrote: > >> On May 18, 2016, at 3:00 PM, Nicola Salmoria via swift-evolution >> <[email protected] <mailto:[email protected]>> wrote: >> >> >> >> On Wed, May 18, 2016 at 8:03 PM, Tony Allevato <[email protected] >> <mailto:[email protected]>> wrote: >> On Wed, May 18, 2016 at 10:02 AM Nicola Salmoria via swift-evolution >> <[email protected] <mailto:[email protected]>> 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 >> <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?
No, it’s not possible today so there is no existing code to reference. However, if you give people a choice some people will inevitably make a different choice than other people. > > I expect the stdlib to illustrate what idiomatic Swift is expected to be, and > people to follow suit for the standard operators. That is exactly what this proposal is attempting to do, and in a way that the language enforces the decision. > > > 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. Are you specifically thinking of assignment operators? If so, I wouldn’t have a problem if the proposal specified assignment operators as instance methods and all other operators as static methods. As long as there is only one way to define a specific operator requirement I will be happy. > > 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. There is no difference in capability here so I’m not sure what you mean by having different “needs”. > > >> >> (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] https://lists.swift.org/mailman/listinfo/swift-evolution
