I'm working with the "Equatable" protocol in some projects, but I'm wondering... What's the actual difference between satisfying the protocol requirements via a global solution and via a static solution (available from swift 3)?
Example:
class ExampleClass {
let value: Int = 0
}
// #1: Global Approach
extension ExampleClass: Equatable { }
func == (lhs: ExampleClass, rhs: ExampleClass) -> Bool {
return lhs.value == rhs.value
}
// #2: Internal static approach (Swift 3+)
extension ExampleClass: Equatable {
static func ==(lhs: ExampleClass, rhs: ExampleClass) -> Bool {
return lhs.value == rhs.value
}
}
The result seems the same, but the second approach seems just cleaner to me. But there's actually a real difference in practice?
At the end we're doing in both cases an overloading.
My possible answer to this is simply that before swift 3 the: public static func ==(lhs: Self, rhs: Self) -> Bool was declared in another way, but I'm just assuming it!
Related
I'm getting a compiler error while adding new protocol conformance to an extension.
struct EquatableStruct { }
extension EquatableStruct: Equatable {
static func == (lhs: EquatableStruct, rhs: EquatableStruct) -> Bool {
return true
}
}
Here I'm getting the compiler error:
Implementation of 'Equatable' cannot be automatically synthesized in an extension
How do I fix this issue?
You are misquoting the error. It should be:
Implementation of 'Equatable' cannot be automatically synthesized in an extension
Comparable extends Equatable. If you want your extension to conform to Comparable you must also implement the Equatable protocol.
extension ComparableStruct: Comparable {
static func < (lhs: ComparableStruct, rhs: ComparableStruct) -> Bool {
return true // FIX
}
static func == (lhs: ComparableStruct, rhs: ComparableStruct) -> Bool {
return true // FIX
}
}
I've looked around, and haven't seen an answer to my question (but maybe I should be able to infer one).
I have an object, based on a protocol. It's an associated type protocol, with class operators that are defined, based on the type assigned to associatedtype, like so:
protocol GenericBaseProtocol {
associatedtype T
var myProperty: T {get set}
init(_ myProperty: T )
}
extension GenericBaseProtocol where T: Equatable {
static func ==(lhs: Self, rhs: Self) -> Bool {
return lhs.myProperty == rhs.myProperty
}
}
So if I create a class, based on this, and give T an Equatable type, like so:
class IntClass: GenericBaseProtocol {
typealias T = Int
var myProperty: T = 0
required init(_ myProperty: T ) {
self.myProperty = myProperty
}
}
The resulting object should be comparable, like so:
let lhs = IntClass(3)
let rhs = IntClass(4)
let isEqual = lhs == rhs
Cool. Now, if I then create an instance with a non-Equatable type, like so:
class ArrayClass: GenericBaseProtocol {
typealias T = [String]
var myProperty: T = []
required init(_ myProperty: T ) {
self.myProperty = myProperty
}
}
And instantiate that, like so:
let lhs2A = ArrayClass(["HI"])
let rhs2A = ArrayClass(["Howaya"])
I will have compile-time syntax errors when I try this:
let isEqual = lhs2A == rhs2A
What I'd like to be able to do, is test the class object of lhs2A, and see if it implements static func ==(lhs: Self, rhs: Self) -> Bool
I'm not sure this can be done, but it would be nice for this article I'm writing up if I could add a runtime/guard proof to the playground, instead of simply commenting out the code.
Any ideas?
You could extend your protocol to give it a default implementation for the == operator in cases where the associated type is not Equatable.
This could also be used to provide a runtime indicator of wether the type is equatable or not.
for example:
extension GenericBaseProtocol where T: Equatable {
static func ==(lhs: Self, rhs: Self) -> Bool {
return lhs.myProperty == rhs.myProperty
}
var isEquatable:Bool { return true }
}
extension GenericBaseProtocol {
static func ==(lhs: Self, rhs: Self) -> Bool {
return false
}
var isEquatable:Bool { return false }
}
Very often you have Int enums like this:
enum Difficulty: Int {
case Easy = 0
case Normal
case Hard
}
Difficulty values have a certain meaning and we may want to introduce order for them. For example, somewhere we need to compare:
let isBonusAvailable = level.difficulty.rawVAlue <= Difficulty.Hard.rawValue
I want to make this code a little bit shorter:
let isBonusAvailable = level.difficulty <= .Hard
It can be easily achieved if I add <= directly to the Difficulty. But I wanted to solve this problem in general, so I tried this super-tricky way:
protocol RawRepresentableByInt {
var rawValue: Int { get }
}
extension RawRepresentableByInt {
static func <(lhs: RawRepresentableByInt, rhs: RawRepresentableByInt) -> Bool {
return lhs.rawValue < rhs.rawValue
}
static func >(lhs: RawRepresentableByInt, rhs: RawRepresentableByInt) -> Bool {
return lhs.rawValue > rhs.rawValue
}
static func <=(lhs: RawRepresentableByInt, rhs: RawRepresentableByInt) -> Bool {
return lhs.rawValue <= rhs.rawValue
}
static func >=(lhs: RawRepresentableByInt, rhs: RawRepresentableByInt) -> Bool {
return lhs.rawValue >= rhs.rawValue
}
}
// Error: Extension of protocol 'RawRepresentable' cannot have an inheritance clause
extension RawRepresentable: RawRepresentableByInt where RawValue == Int {
}
It produces a compiler error:
Error: Extension of protocol 'RawRepresentable' cannot have an inheritance clause
I think there is nothing unimplementable in comparison of Int enum in term of logic. Please, help me to trick the Swift compiler. Anyone, who also need such extensions may participate.
It was easier than I thought. So, basically you can use Self instead of creating an additional protocol.
enum Difficulty: Int {
case Easy = 0
case Normal
case Hard
}
extension RawRepresentable where RawValue: Comparable {
static func <(lhs: Self, rhs: Self) -> Bool {
return lhs.rawValue < rhs.rawValue
}
static func >(lhs: Self, rhs: Self) -> Bool {
return lhs.rawValue > rhs.rawValue
}
static func <=(lhs: Self, rhs: Self) -> Bool {
return lhs.rawValue <= rhs.rawValue
}
static func >=(lhs: Self, rhs: Self) -> Bool {
return lhs.rawValue >= rhs.rawValue
}
}
let easy = Difficulty.Easy
print(easy > .Hard) // false
I am a bit stuck trying to define a container for my ui elements.
As I wanted something that encapsulates a non unique label, a value that can be any comparable object and a concept of being the preferred option I came up with the following protocol:
protocol OptionProtocol:Comparable {
associatedtype Key:Comparable
associatedtype Value:Comparable
var key:Key { get set }
var value:Value { get set }
var main:Bool { get set }
static func <(lhs: Self, rhs: Self) -> Bool
static func ==(lhs: Self, rhs: Self) -> Bool
}
extension OptionProtocol {
static func <(lhs: Self, rhs: Self) -> Bool {
let equalKeys = lhs.key == rhs.key
return equalKeys ? lhs.value < rhs.value : lhs.key < rhs.key
}
static func ==(lhs: Self, rhs: Self) -> Bool{
return (lhs.value == rhs.value) && (lhs.key == rhs.key)
}
}
Now I want to implement the protocol in a generic struct and I cant figure out how. What I want to do is
struct Option<Key, Value>: OptionProtocol {
var key:Key
var value:Value
var main:Bool
}
But the compiler complains that Type 'Option<Key, Value>' does not conform to protocol 'OptionProtocol'
Any pointer would be helpful
The answer was pretty simple. I needed to constraint Key and Value in the struct.
The following struct compiles as expected
struct Option<Key, Value>:OptionProtocol where Key:Comparable, Value:Comparable {
var key:Key
var value:Value
var main:Bool
}
I'm trying to implement the Comparable protocol in Swift, but the compiler doesn't like any of my attempts to overload the < operator. I've checked the Apple documents and all the SO posts, but none of them even compile. Xcode gives me this warning:
Consecutive declarations on a line must be separated by ';'
and it keeps recommending me to insert a semicolon after the less than symbol. Any insight on what I'm doing wrong is appreciated.
class SomeClass: NSObject, Equatable, Comparable{
var number: UInt32!
override init()
{
super.init()
self.number = arc4random()
}
func == (lhs: SomeClass, rhs: SomeClass) -> Bool
{
return true
}
func < (lhs: SomeClass, rhs: SomeClass) -> Bool
{
return true
}
}
You see this error, because operators have to be overloaded outside the class definition, e.g. move
func == (lhs: SomeClass, rhs: SomeClass) -> Bool
{
return true
}
func < (lhs: SomeClass, rhs: SomeClass) -> Bool
{
return true
}
outside your class definition and it will work (except for that they do not return the proper result with this implementation).