[swift-evolution] [swift-evolution-announce] [Review] SE-0067: Enhanced Floating Point Protocols

Tony Allevato allevato at google.com
Wed Apr 27 14:03:41 CDT 2016


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`.

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).


>>
> >> 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. In this case,
the compiler would automatically generate the global trampoline operator:

    func += <T: TheProtocol>(lhs: inout T, rhs: T) { T.+=(&x, y) }

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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160427/8f82bfc1/attachment.html>


More information about the swift-evolution mailing list