On Wed, May 18, 2016 at 3:56 PM, Matthew Johnson <[email protected]> wrote:
> > On May 18, 2016, at 3:48 PM, Xiaodi Wu via swift-evolution < > [email protected]> wrote: > > > > On Wed, May 18, 2016 at 3:37 PM, Nicola Salmoria via swift-evolution < > [email protected]> wrote: > >> >> >> On Wed, May 18, 2016 at 10:27 PM, Tony Allevato <[email protected]> >> wrote: >> >>> On Wed, May 18, 2016 at 1:00 PM Nicola Salmoria < >>> [email protected]> wrote: >>> >>>> On Wed, May 18, 2016 at 8:03 PM, Tony Allevato <[email protected]> >>>> wrote: >>>> >>>>> On Wed, May 18, 2016 at 10:02 AM Nicola Salmoria via swift-evolution < >>>>> [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) >>>>>> >>>>>> 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. >>>> >>> >>> What I'm saying is, if you look at the Swift 3 branch of stdlib, global >>> operator functions still do not have argument labels. Picking one at >>> random: >>> https://github.com/apple/swift/blob/swift-3.0-branch/stdlib/public/core/String.swift#L329 >>> >>> If you're arguing that those functions should be forced to include `_` >>> placeholders, that's fine, but it's not accurate to say that the way >>> they're written in this proposal is a step backwards from all the progress >>> made in Swift 3. It is *consistent* with the way global operator functions >>> are currently declared in Swift 3. >>> >>> If it changes there, then it should change here as well. But they should >>> be the same, and making that change for global operator functions is not >>> part of the scope of this proposal. >>> >> >> I'm not talking about the global operator functions; I'm talking about >> the methods inside the protocol, which are methods and are called like >> methods; they are not operators. >> >> > Thanks for expressing this so clearly. I'm of the same feeling but fumbled > the communication of it. > > On re-evaluation, I wonder if this proposal as it is would be a > sufficiently large improvement. It's essentially permitting the use of > characters reserved for operators in static method names, but it adds a set > of somewhat inconsistent rules for how those functions are to be declared > and called. As mentioned earlier, `T....(x, y)` looks rather unfortunate, > and since automatic trampolines are out of scope, I wonder if what we have > currently (naming static methods using words) is altogether that bad. Maybe > we could just standardize those names and be done with it; on a cursory > look, that seems to be Rust's approach. > > > 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. > Yeah, also good points. Can I propose maybe another approach? ``` T.operator(+, a, b) T.operator(prefix: ++, a) T.operator(postfix: ++, a) ``` > 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. > > > >> >> >>> >>> >>> >>>> >>>> >>>>> >>>>> >>>>>> 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] >>>>>> 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 > > >
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
