> On May 18, 2016, at 3:00 PM, Nicola Salmoria via swift-evolution > <[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. What benefit do you perceive in allowing operator instance methods? > > (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] > https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
