[swift-evolution] [Proposal] Instance Operators

Nicola Salmoria nicola.salmoria at gmail.com
Fri Feb 26 09:35:34 CST 2016


If the argument symmetry should be preserved, I think I'd still prefer to
leave operators out of this, and consistently use static methods, like this:

public protocol IntegerArithmeticType {
    public static func add(lhs: Self, _ rhs: Self) -> Self
    public static func addWithOverflow(lhs: Self, _ rhs: Self) -> (Self,
overflow: Bool)
}

public func +<T: IntegerArithmeticType>(lhs: T, rhs: T) -> T {
    return T.add(lhs, rhs)
}
public func &+<T: IntegerArithmeticType>(lhs: T, rhs: T) -> T {
    return T.addWithOverflow(lhs, rhs).0
}


public protocol Equatable {
    public static func equal(lhs: Self, _ rhs: Self) -> Bool
}

public func ==<T: Equatable>(lhs: T, rhs: T) -> T {
    return T.equal(lhs, rhs)
}
public func !=<T: Equatable>(lhs: T, rhs: T) -> T {
    return !T.equals(lhs, rhs)
}


--
Nicola


On Fri, Feb 26, 2016 at 4:18 PM, Thorsten Seitz <tseitz42 at icloud.com> wrote:

> I don't think symmetric operators should be mapped to asymmetric methods
> which are only dispatched on the receiver's type.
>
> Of course the current scheme using global functions with no dynamic
> dispatch at all is not much better (the selected function depends on the
> static types I happen to see at the call site but at least it isn't
> preferring one of the arguments.
> Having real multiple dispatch would be nice :-)
>
> -Thorsten
>
> Am 26.02.2016 um 11:41 schrieb Nicola Salmoria via swift-evolution <
> swift-evolution at swift.org>:
>
> I’m wondering if we might be trying to solve the wrong problem here.
>
> Let’s look for example at part of the definition of the
> IntegerArithmeticType protocol (disregarding implementation details):
>
> public protocol IntegerArithmeticType {
>
>     public func +(lhs: Self, rhs: Self) -> Self
>
>     public static func addWithOverflow(lhs: Self, _ rhs: Self) -> (Self,
> overflow: Bool)
> }
>
> There’s an obvious asymmetry here: + is defined as “public func”, while
> addWithOverflow is “public static func”.
>
> Perhaps instead of extending how operators are defined, it would be more
> efficient to reconsider how protocol conformance should be defined.
> It seems to me that a ‘swifter’ way to do the above would be
>
> public protocol IntegerArithmeticType {
>
>     public func add(to: Self) -> Self
>
>     public func addWithOverflow(to: Self) -> (Self, overflow: Bool)
> }
>
> and then generic operators can simply be defined once at global scope:
>
> public func +<T: IntegerArithmeticType>(lhs: T, rhs: T) -> T {
> return lhs.add(hrs)
> }
>
> public func &+<T: IntegerArithmeticType>(lhs: T, rhs: T) -> T {
> return lhs.addWithOverflow(hrs).0
> }
>
>
> Equatable and Comparable have similar asymmetries:
>
> /// Instances of conforming types can be compared for value equality
> /// using operators `==` and `!=`.
> ///
> /// When adopting `Equatable`, only the `==` operator is required to be
> /// implemented.  The standard library provides an implementation for `!=`.
> public protocol Equatable {
>     public func ==(lhs: Self, rhs: Self) -> Bool
> }
>
> so we need to define ==, but not != because it’s derived from the former.
> Again, the cause of the inconsistency is the requirement to define the
> operator as part of the protocol conformance. If it was done like this, it
> might seem simpler and more symmetrical:
>
> public protocol Equatable {
>     public func equals(other: Self) -> Bool
> }
>
> public func ==<T: Equatable>(lhs: T, rhs: T) -> T {
> return lhs.equals(hrs)
> }
> public func !=<T: Equatable>(lhs: T, rhs: T) -> T {
> return !lhs.equals(hrs)
> }
>
> Nicola
>
> > Hello.
> >
> > The proposal can be also read
> athttps://gist.github.com/vmartinelli/67d6ad234c7a4e14f8d5
> >
> > Original thread:https://
> lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160125/008508.html
> >
> > Opinions, comments and corrections (including on English grammar) are
> all welcome. :-)
> >
> > -Van
> >
> > ---------
> >
> > Instance Operators
> > Proposal:SE-NNNN(
> https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-instance-operators.md
> )
> > Author:Vanderlei Martinelli(https://github.com/vmartinelli)
> > Status:Awaiting review
> > Review manager: TBD
> >
> > Introduction
> >
> > The proposal aims to move operator implementation from the global and
> static scope into extension/struct/class instance scope.
> >
> >
> > Swift-evolution thread:link to the discussion thread for that proposal(
> https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160125/008508.html
> )
> >
> > Motivation
> >
> > When writing the protocol interface the operator is declarated inside
> the scope of that protocol, but its implementation has to be static and
> global. This, besides being inconsistent, might not the behaviour expected
> by programmers coming from other languages that have some kind of support
> for interface/protocol and operator implementation.
> >
> >
> > Example:
> >
> > // MARK: - protocolpublicprotocolMyDoubleType
> {publicfuncsomeUsefulFunction()publicfunc*(lhs:Self,
> rhs:Self)->Selfpublicpostfixfunc++(inoutx:Self)->Self }// MARK: -
> implementationextensionDouble: MyDoubleType {publicfuncsomeUsefulFunction()
> {// ...}// we cannot implement the operators here...}// ... but have to
> implement them herepublicfunc*(lhs:Double,
> rhs:Double)->Double{returnlhs.multipliedBy(rhs)
> }publicpostfixfunc++(inoutx:Double)->Double{   x+=1.0returnx }
> >
> >
> > Also the current implementation does not leave much room for future
> expansion in the use of operators (such as conversion between values, for
> example).
> >
> > Proposed solution
> >
> > Move the operator implementation into the extension/struct/class scope
> and turn operator funcs into instance funcs, using theoperatorkeyword.
> >
> > Detailed design
> > Protocol conformance
> >
> > After the change the above code can be written like the example bellow.
> >
> > // MARK: - protocolpublicprotocolMyDoubleType
> {publicfuncsomeUsefulFunction()publicoperator*(rhs:Self)->Selfpublicmutatingpostfixoperator++()->Self}//
> MARK: - implementationextensionDouble: MyDoubleType
> {publicfuncsomeUsefulFunction() {//
> ...}publicoperator*(rhs:Double)->Double{returnself.multipliedBy(rhs)
> }publicmutatingpostfixoperator++()->Double{self+=1.0returnself} }
> >
> > Operator funcs everywhere
> >
> > An operator does not have to be implemented only to conform to a
> protocol, however. It can be also be implemented in any other place where a
> common func is. This means that even the current form can be supported.
> >
> > Operator internal names
> >
> > Perhaps because of the internal implementation of Swift, operators have
> to have names to be handled. The suggestion is to
> adopt__operator__GreaterThanOrEqualfor a>=operator, as example. The
> operator introduction would be:
> >
> > infixoperator>={associativitynoneprecedence130name"GreaterThanOrEqual"}
> >
> >
> > So the code will be written like this...
> >
> > structMyStruct {operator>=(other: MyStruct)->Bool{return...} }
> >
> >
> > ... but translated internally to this:
> >
> > structMyStruct {func__operator__GreaterThanOrEqual(other:
> MyStruct)->Bool{return...} }
> >
> > Impact on existing code
> >
> > Since after this change an operator can be implemented in any other
> place where a common func can be, the current implementation may continue
> to exist, but marked as deprecated with a compiler/analyser warning.
> >
> >
> > Also thefunckeyword would be deprecated for operators as well, using
> theoperatorto declare/implement an operator func.
> >
> > Alternatives considered
> > Status quo
> >
> > Leave things as they are. Even being inconsistent or not allowing new
> possibilities that instance operators will bring.
> >
> > Static implementation inside extension/struct/class scope
> >
> > This is the way operators are implemented in C#, for example. The change
> would be only aesthetic. The functionality would remain the same as today.
> >
> >
> > As the types may differ from protocol/structure/class, this would allow
> state within the scope of operators that have nothing to do with that type.
> Not a good thing. In this case it might be better to keep things as they
> are.
> >
> >
> > Example:
> >
> > // MARK: - protocolpublicprotocolMyDoubleType
> {publicfuncsomeUsefulFunction()publicstaticoperator*(lhs:Self,
> rhs:Self)->Selfpublicstaticoperator/(lhs:Int64, rhs:Int64)->Int64//
> what?publicstaticpostfixoperator++(inoutx:Self)->Self}// MARK: -
> implementationextensionDouble: MyDoubleType {publicfuncsomeUsefulFunction()
> {// ...}publicstaticoperator*(lhs:Double,
> rhs:Double)->Double{returnlhs.multipliedBy(rhs)   }// this should be
> implemented inside a Int64 type, not
> here...publicstaticoperator/(lhs:Int64, rhs:Int64)->Int64{//
> ...}publicstaticpostfixoperator++(inoutx:Double)->Double{
> x+=1.0returnx   } }
> >
> >
> >
> >
>
> _______________________________________________
> 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/20160226/8303a256/attachment.html>


More information about the swift-evolution mailing list