Overloading Operators in Swift - swift

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

Related

Overload Equality Operator (==) to compare String and Int

I am experiencing with protocols and challenged myself to write a code snippet that overloads the == operator so that it returns true when I compare a random String with value "42" with a Int of value 42. Please don't question the usefulness by simply returning 42 on a String, the main point is getting the Equality Operator to run on the two different types.
Here is what I tried:
Version 1
import Foundation
protocol IntTransformable: Equatable {
func toInt() -> Int
}
extension String: IntTransformable {
func toInt() -> Int {
return 42
}
}
extension Int: IntTransformable {
func toInt() -> Int {
return self
}
}
extension IntTransformable {
static func == (lhs: Self, rhs: Self) -> Bool {
return lhs.toInt() == rhs.toInt()
}
}
// throws: Ambiguous reference to operator function '=='
if "42" == 42 {
print("equal")
} else {
print("unequal")
}
Version 2
import Foundation
protocol IntTransformable: Equatable {
func toInt() -> Int
}
extension String: IntTransformable {
func toInt() -> Int {
return 42
}
}
extension Int: IntTransformable {
func toInt() -> Int {
return self
}
}
extension IntTransformable {
// throws: Protocol 'IntTransformable' can only be used as a generic constraint because it has Self or associated type requirements
static func == (lhs: IntTransformable, rhs: IntTransformable) -> Bool {
return lhs.toInt() == rhs.toInt()
}
}
// throws: Ambiguous reference to operator function '=='
if "42" == 42 {
print("equal")
} else {
print("unequal")
}
You should use these two functions:
func ==(lhs: String, rhs: #autoclosure ()->Int) -> Bool {
guard let stringIntValue = Int(lhs) else { return false }
return stringIntValue == rhs()
}
func ==(lhs: Int, rhs: String) -> Bool {
guard let stringIntValue = Int(rhs) else { return false }
return lhs == stringIntValue
}
But if you really want to involve Protocols here, you should do this like:
extension IntTransformable {
static func ==<T: IntTransformable>(lhs: Self, rhs: T) -> Bool {
return lhs.toInt() == rhs.toInt()
}
}
Usage:
print( 42 == "42" )
print( "42" == 42 )
You're way overthinking this. There is no reason to use protocols here, and you really can't do it because protocols are not really types. Just write your operator(s) at top level:
func == (lhs: Int, rhs: String) -> Bool {
return lhs == Int(rhs)
}
func == (lhs: String, rhs: Int) -> Bool {
return Int(lhs) == rhs
}
Testing:
print(5 == "5") // true
create a string extension, like
public string ToInt(this int value)
{
// some conversion code
return ConvertedStringValue;
}
or you can use a uint.TryParse(string value, out uint output)
this statement will return true if conversion is successful.

operator '<' declared in type 'XXX' must be 'static'

I have the following implementation and also added Comparable extension as follows. But I am getting the following error. I wonder how I could able to fix it.
error: operator '<' declared in type 'Item' must be 'static'
func < (lhs: Item, rhs: Item) -> Bool {
^
static
class Item
{
var timeStamp : Date
var value : Int
init(_ value: Int)
{
self.value = value
self.timeStamp = Date()
}
}
extension Item: Comparable
{
func < (lhs: Item, rhs: Item) -> Bool {
return lhs.timeStamp < rhs.timeStamp
}
func == (lhs: Item, rhs: Item) -> Bool {
return lhs.timeStamp == rhs.timeStamp
}
}
The Comparable protocol requires that the < operator implementation is static. It is documented here. You could fix your code by adding the static keyword like so:
static func < (lhs: Item, rhs: Item) -> Bool {
return lhs.timeStamp < rhs.timeStamp
}

How to fix `Implementation of 'Protocol' cannot be automatically synthesized in an extension`?

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
}
}

Swift 3.+ Conforming Equatable - Internal and static OR global approach?

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!

Extend Int enum with comparison operators

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