[swift-evolution] [swift-evolution-announce] [Review] SE-0067: Enhanced Floating Point Protocols
Dave Abrahams
dabrahams at apple.com
Wed Apr 27 15:14:28 CDT 2016
on Wed Apr 27 2016, Tony Allevato <allevato-AT-google.com> wrote:
> On Wed, Apr 27, 2016 at 11:07 AM Dave Abrahams via swift-evolution
> <swift-evolution at swift.org> wrote:
>
> on Wed Apr 27 2016, Stephen Canon <swift-evolution at swift.org> wrote:
>
> >> On Apr 27, 2016, at 1:54 PM, Dave Abrahams via swift-evolution
> <swift-evolution at swift.org> wrote:
> >>
> >> on Tue Apr 26 2016, Chris Lattner <swift-evolution at swift.org> wrote:
> >>
> >>> On Apr 26, 2016, at 7:34 PM, Tony Allevato via swift-evolution
> <swift-evolution at swift.org> wrote:
> >
> >>>> Would something like this be possible? Imagine protocols defined like
> this:
> >>>>
> >>>> public protocol Equatable {
> >>>> static func == (lhs: Self, rhs: Self) -> Self
> >>>> }
> >>>
> >>> The problem is that every type that conforms to Equatable has to
> >>> provide an overload of == in order to conform. This is exactly what
> >>> having named methods as requirements solves.
>
> Forgive me, but I'm not following you here. How would that differ from every
> type that conforms to `FloatingPoint` (or `Equatable`, if we modeled it the same
> way) having to provide an overload of `isEqual` if a generic `==<T:
> FloatingPoint>` (or `==<T: Equatable>`) was implemented in terms of that named
> method?
>
> If the issue is with class hierarchies and dynamic dispatch, the conforming
> class can make `==` a class method instead of a static one, and then subclasses
> can either (1) inherit the base class implementation if they don't need to
> change anything, or (2) override and extend it. Thus, `T.==(lhs, rhs)` should
> dynamically dispatch to the same thing `lhs.isEqual(rhs)` would (since the
> arguments in the protocol are of type `Self`).
>
> >>
> >> Note that Tony is proposing to make the requirement static. Whether
> >> it's actually called “==” or isEqual is almost immaterial, because the
> >> fact that it is static makes it less likely that anyone will try to call
> >> it directly.
> >>
> >> However, if we allowed static operators to be defined, and called using
> >> the syntax “T.==(x,y)”, as Tony has suggested, IMO it would further
> >> discourage direct use, and it would avoid growing the number of
> >> truly distinct spellings for the same operation.
>
> Exactly—and in that sense, I would argue that the choice of name isn't quite
> immaterial, because `==` matches the global operator name while `isEqual` is
> arbitrary and user-chosen. This would avoid situations where one person might
> implement `==` with a method named `isEqual` and another might use
> `isSame`.
That's why I said *almost* immaterial.
> Granted, we already have some places where operators duplicate functionality of
> named methods (like `Array` mapping `+=` to `appendContentsOf`), but this
> approach at least lets the author of the protocol and its types use the operator
> name itself as the *sole and primary* name of the function when the context is
> such that that makes the most sense (such as arithmetic contexts) and coming up
> with alternative names would be either awkward or increase potential for
> confusion by increasing the API surface and giving the user two ways to do the
> same thing (when it might not be obvious if they actually do the exact same
> thing).
Hey, I agree with you.
> >>
> >> That would also remove many instances of “formXXX” methods that
> >> currently cause many people discomfort. Whether that's a win or not
> >> depends on whether you view widespread discomfort with “formXXX” as a
> >> nuisance or a beneficial forcing function for finding something better
> >> ;-)
>
> >
> > Personally I like this, but t’s not totally clear how it would extend
> > to mutating operations. `T.+=(x: inout T, y: T)`?
>
> Well, that looks like a mix between a decl and a use. I presume you
> mean
>
> static func +=(x: inout T, y: T)
>
> and
>
> T.+=(&x, y)
>
> That seems like the obvious answer to me.
>
> Precisely. The signature would be exactly the same as the global function, just
> declared static in the protocol instead of non-static.
The one possible alternative I thought of would be to support infix
notation, e.g.
x T.+= y
It might come down to what's easier to parse.
> In this case, the compiler would automatically generate the global
> trampoline operator:
>
> func += <T: TheProtocol>(lhs: inout T, rhs: T) { T.+=(&x, y) }
Whoops: I didn't realize you were talking about doing that
automatically. IMO the minimal change that could possibly fit in Swift
3 would be to allow static operator declarations and calls, and have the
library declare the trampolines. If there's time to go further, I
wouldn't necessarily be opposed, but at this point it's extremely late
to do anything ambitious.
Keep in mind though that several people in the community have long held
that operators should be regular members, which presumably would
obsolete these static members. On the other hand, we don't have a
design for that change, which I think would require defining a new set
of lookup rules. This is probably an incremental step in the right
direction.
> Users could still refer to `T.+=` directly to obtain a reference to the `(inout
> T, T) -> Void` function, but would likely only need to do this in the context of
> generic algorithms, and then only in situations where the compiler needed more
> help inferring the argument types (if `+=` by itself didn't provide enough
> context).
>
> >
> >
> > – Steve
> >
> > _______________________________________________
> > swift-evolution mailing list
> > swift-evolution at swift.org
> > https://lists.swift.org/mailman/listinfo/swift-evolution
>
> --
> Dave
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
--
Dave
More information about the swift-evolution
mailing list