Why must a protocol operator be implemented as a global function?
UPDATE
From the Xcode 8 beta 4 release notes:
Operators can be defined within types or extensions thereof. For example:
struct Foo: Equatable {
let value: Int
static func ==(lhs: Foo, rhs: Foo) -> Bool {
return lhs.value == rhs.value
}
}
Such operators must be declared as
static
(or, within a class,class final
), and have the same
signature as their global counterparts. As part of this change, operator requirements declared in
protocols must also be explicitly declaredstatic
:protocol Equatable {
static func ==(lhs: Self, rhs: Self) -> Bool
}
ORIGINAL
This was discussed on the swift-evolution list recently (2016-01-31 through 2016-02-09 so far). Here's what Chris Lattner said, regarding declaring operators in a struct or class scope:
Yep, this is a generally desirable feature (at least for symmetric operators). This would also be great to get dynamic dispatch of operators within class declarations. I don’t think we have a firm proposal nailing down how name lookup works with this though.
And later (replying to Haravikk):
What are the name lookup issues? Do you mean cases where an operator for Foo == Foo exists in more than one location?
Yes. Name lookup has to have a well defined search order, which
defines shadowing and invalid multiple definition rules.Personally I’d just stick with what we have now, i.e- treat operator implementations within a specific class/struct as being globally
defined anyway and throw an error if the same signature is declared
more than once.
We need multiple modules to be able to define instances of an
operator, we need operators in extensions, and we need retroactive
conformance to work, as with any other member.
I don`t know why error happen
Try having a look at this answer
Your ==
method should not be added in an extension
, it should be added globally. Even though it might seem to be a static
method, it should still be declared as a global function. You can find a discussion about the details here.
Now...if you had declared your Post
as a struct
or a class
then yes, you could have added a static ==
method inside your struct/class
. However, you have declared a protocol
and a protocol
can not have any methods.
This answer shows you how to have a protocol
implement Equatable
.
Armed with all that we can implement your Post protocol
and have it implement Equatable
like so:
protocol Post: Equatable {
var referenceIndex: Int { get set}
var likeCount: Int { get set}
var likeStatus: Bool { get set}
var commentCount: Int { get set}
var commentStatus: Bool { get set}
}
func ==<T : Post>(lhs: T, rhs: T) -> Bool {
return lhs.referenceIndex == rhs.referenceIndex
}
And then, to prove that things are working:
struct SomePost: Post {
var referenceIndex: Int
var likeCount: Int
var likeStatus: Bool
var commentCount: Int
var commentStatus: Bool
}
let somePost1 = SomePost(referenceIndex: 1, likeCount: 1, likeStatus: true, commentCount: 1, commentStatus: true)
let somePost2 = SomePost(referenceIndex: 2, likeCount: 1, likeStatus: true, commentCount: 1, commentStatus: true)
let somePost3 = SomePost(referenceIndex: 1, likeCount: 1, likeStatus: true, commentCount: 1, commentStatus: true)
somePost1 == somePost2 //false
somePost1 == somePost3 //true
Hope that helps you
Why a equatable protocol needs to be defined outside the class?
Mainly because it's a function and not a method. Functions are independent on classes so it makes no sense to scope them inside class declarations.
The protocol could have been designed with methods, e.g. using a obj1.isEqualTo(obj2)
method but a function is less sensitive to nil
problems. If obj1
were nil
, the method would fail.
Swift ambiguous overloaded + operator
The +
operator shouldn't be inside the extension, but rather a global func
. Replace your definition of +
:
extension Number {
static func + (lhs: Number, rhs: Number) -> Number {
return SimpleNumber(lhs.doubleValue + rhs.doubleValue)
}
}
with simply
func + (lhs: Number, rhs: Number) -> Number {
return SimpleNumber(lhs.doubleValue + rhs.doubleValue)
}
and it will work. I guess what you have done is created a static function Number.+
, not the global function +
that you are using...
Swift Equatable Protocol
Move this function
func == (lhs: Cookie, rhs: Cookie) -> Bool {
return lhs.column == rhs.column && lhs.row == rhs.row
}
Outside of the cookie class. It makes sense this way since it's overriding the == operator at the global scope when it is used on two Cookies.
understanding protocol extensions in swift
As touched on in this Q&A, there's a difference between operator overloads implemented as static
members and operator overloads implemented as top-level functions. static
members take an additional (implicit) self
parameter, which the compiler needs to be able to infer.
So how is the value of self
inferred? Well, it has to be done from either the operands or return type of the overload. For a protocol extension, this means one of those types needs to be Self
. Bear in mind that you can't directly call an operator on a type (i.e you can't say (Self.<)(a, b)
).
Consider the following example:
protocol Value {
func get() -> Float
}
extension Value {
static func < (a: Value, b: Value) -> Bool {
print("Being called on conforming type: \(self)")
return a.get() < b.get()
}
}
struct S : Value {
func get() -> Float { return 0 }
}
let value: Value = S()
print(value < value) // Ambiguous reference to member '<'
What's the value of self
in the call to <
? The compiler can't infer it (really I think it should error directly on the overload as it's un-callable). Bear in mind that self
at static scope in a protocol extension must be a concrete conforming type; it can't just be Value.self
(as static methods in protocol extensions are only available to call on concrete conforming types, not on the protocol type itself).
We can fix both the above example, and your example by defining the overload as a top-level function instead:
protocol Value {
func get() -> Float
}
func < (a: Value, b: Value) -> Bool {
return a.get() < b.get()
}
struct S : Value {
func get() -> Float { return 0 }
}
let value: Value = S()
print(value < value) // false
This works because now we don't need to infer a value for self
.
We could have also given the compiler a way to infer the value of self
, by making one or both of the parameters take Self
:
protocol Value {
func get() -> Float
}
extension Value {
static func < (a: Self, b: Self) -> Bool {
print("Being called on conforming type: \(self)")
return a.get() < b.get()
}
}
struct S : Value {
func get() -> Float { return 0 }
}
let s = S()
print(s < s)
// Being called on conforming type: S
// false
The compiler can now infer self
from the static type of operands. However, as said above, this needs to be a concrete type, so you can't deal with heterogenous Value
operands (you could work with one operand taking a Value
; but not both as then there'd be no way to infer self
).
Although note that if you're providing a default implementation of <
, you should probably also provide a default implementation of ==
. Unless you have a good reason not to, I would also advise you make these overloads take homogenous concrete operands (i.e parameters of type Self
), such that they can provide a default implementation for Comparable
.
Also rather than having get()
and set(to:)
requirements, I would advise a settable property requirement instead:
// Not deriving from Comparable could be useful if you need to use the protocol as
// an actual type; however note that you won't be able to access Comparable stuff,
// such as the auto >, <=, >= overloads from a protocol extension.
protocol Value {
var floatValue: Double { get set }
}
extension Value {
static func == (lhs: Self, rhs: Self) -> Bool {
return lhs.floatValue == rhs.floatValue
}
static func < (lhs: Self, rhs: Self) -> Bool {
return lhs.floatValue < rhs.floatValue
}
}
Finally, if Comparable
conformance is essential for conformance to Value
, you should make it derive from Comparable
:
protocol Value : Comparable {
var floatValue: Double { get set }
}
You shouldn't need a min(of:and:)
function in either case, as when the conforming type conforms to Comparable
, it can use the top-level min(_:_:)
function.
Swift 4.0 Difference between implementing custom operator inside a type as a type method and in global scope as a global function
With
infix operator >>> : FunctionCompositionPrecedence
extension Parser {
public static func >>> <A, B> (lhs: Parser<A>, rhs: Parser<B>)
-> Parser<(A,B)> {
return lhs.followed(by: rhs)
}
}
You've provided no way for the compiler to infer the generic placeholder Result
on calling the operator (really I think the compiler should error here rather than on usage). Remember that static methods on generic types are called on specialisations of those types; the placeholders must be satisfied (as they're accessible at static scope).
So to directly answer
what is the difference between the first implementation and the second one.
The main difference is that as a static member, you have the additional generic placeholder Result
that needs to be satisfied; as a top-level function, you don't have that.
So, if you want to keep >>>
as a static method, you'll want to use the Result
placeholder in the signature of your operator implementation such that the compiler can infer its type on usage, for example:
infix operator >>> : FunctionCompositionPrecedence
extension Parser {
public static func >>> <B> (
lhs: Parser, rhs: Parser<B>
) -> Parser<(Result, B)> {
return lhs.followed(by: rhs)
}
}
Now Result
can be inferred from the type of the argument passed as the lhs
of the operator (Parser
is syntactic sugar for Parser<Result>
in this context).
Note you'll face a similar problem with
extension Parser {
public static func apply <A, B> (_ lhs: Parser<(A)->B>, _ rhs: Parser<A>) -> Parser<B> {
return (lhs >>> rhs).map{(arg) -> B in let (f, x) = arg; return f(x)}
}
}
in that you'll need to explicitly satisfy the Result
placeholder when calling; although the type used to satisfy it won't actually be used by the method.
Better would be to use the Result
placeholder in the signature to allow the compiler to infer it at the call-site:
extension Parser {
public static func apply<Arg>(
_ lhs: Parser<(Arg) -> Result>, _ rhs: Parser<Arg>
) -> Parser<Result> {
return (lhs >>> rhs).map { arg -> Result in
let (f, x) = arg
return f(x)
}
}
}
// ...
let p = Parser<(String) -> String> { input in ({ $0 + input }, "hello") }
let p1 = Parser { ($0, "") }
let p2 = Parser.apply(p, p1)
print(p2.run(" world") as Any) // Optional(("hello world", ""))
Or, better still, as an instance method:
extension Parser {
public func apply<A, B>(with rhs: Parser<A>) -> Parser<B>
where Result == (A) -> B {
return (self >>> rhs).map { arg -> B in
let (f, x) = arg
return f(x)
}
}
}
// ...
let p = Parser<(String) -> String> { input in ({ $0 + input }, "hello") }
let p1 = Parser { ($0, "") }
let p2 = p.apply(with: p1)
print(p2.run(" world") as Any) // Optional(("hello world", ""))
Implement Equatable for custom private class - Swift
You need to also declare your ==
operator function as private
for this to work. Functions are by default scoped as internal
, and you can't have an internal method with privately scoped parameters or return type.
private class Foo : Equatable {
var bar = ""
}
private func ==(lhs: Foo, rhs: Foo) -> Bool {
return lhs.bar == rhs.bar
}
Related Topics
Nspredicate for Array of Dictionaries
Get the Callers Phone Number from an Incoming Call on Iphone
Swift: Gradient Along a Bezier Path (Using Calayers)
How to Query Nearest Users in Firebase with Swift
Swift Execute Asynchronous Tasks in Order
Switching from Xcode3 to Xcode4 - Can't Load Programs Onto Older Ipod Touch
Always Got Nil Value from the Function in iOS
Date Formats from Device Based on Locale
Best Analytics Offering for Iphone
Universal Links Not Working on iOS10
Clip Image to Square in Swiftui
Array of Multiple Url's Nsfilemanager Swift
#If Canimport() Does Not Find Frameworks with Cocoapods