Compare 2 structs/Objects implement the same Protocol? - swift

let's say I have the following :
protocol P : Equatable {
var uniqueID : Int { get }
}
struct A : P {
var uniqueID = 1
}
struct B : P {
var uniqueID = 2
}
func ==<T : P>(lhs:T , rhs:T) -> Bool { return lhs.uniqueID == rhs.uniqueID }
Now when I write the following:
let a = A()
let b = B()
let c = a == b
I got error: binary operator '==' cannot be applied to operands of type 'A' and 'B'
is there any way to achieve this ?

you have to define the equality function with two generic types to allow different types to be compared, like this:
func ==<T: P, T2: P>(lhs: T , rhs: T2) -> Bool { return lhs.uniqueID == rhs.uniqueID }

Related

Swift - Struct with equatable variable

I'm trying to implement a struct which is Equatable and has a variable (in this example 'variable2') of type AnyObject that might or not be equatable.
struct MyStruct : Equatable{
var variable1 : String;
var variable2 : AnyObject;
}
func == (obj1 : MyStruct, obj2 : MyStruct) -> Bool {
if(obj1.variable2.conformsToProtocol(Equatable) && obj2.variable2.conformsToProtocol(Equatable)) {
//...
} else {
//...
}
return ...
}
At first I was trying to check if variable2 conforms to protocol Equatable, but doing so i get a compile error.
On a different approach I tried to change 'variable2' to Equatablebut even so I still have an error telling me it can only be used as a generic constraint.
struct MyStruct : Equatable{
var variable1 : String;
var variable2 : Equatable;
}
func == (obj1 : MyStruct, obj2 : MyStruct) -> Bool {
return obj1.variable2 == obj2.variable2;
}
I tried some different ways, but didn't manage to get it to work. Does anyone has a solution for this?Solving the first case would be the best situation, but the second might satisfy my needs as well.
Why not use the "is" operator:
if obj1.variable2 is Equatable && obj2.variable2 is Equatable {
...
}
(a) AnyObject doesn't conforms to Equatable
(b) If you downcast some class which conforms to Equatable to AnyObject,
the result is NOT equatable!!
class C: Equatable {
var i: Int
init(value: Int){
i = value
}
}
func ==(lhs: C, rhs: C)->Bool {
return 2 * lhs.i == rhs.i
}
let c1 = C(value: 1)
let c2 = C(value: 2)
c1 == c2 // true
let a1 = c1 as AnyObject
let a2 = c2 as AnyObject
// or if you want
// let a1: AnyObject = c1
// let a2: AnyObject = c2
// a1 == a2 // error!!!
a1 as? C == a2 as? C // true
In other words, you are not able to compare two AnyObject. You can check if two references to AnyObject are the same (representing the same instance). But that has nothing with Equatable protocol.

How to construct generic without protocol in Swift?

I'm getting the following error...
'T' cannot be constructed because it has no accessible initializers
When compiling...
class Sub<T : Equitable> {
func def(v : T) -> Bool{
var d = T() // <- Error
return d == v
}
}
var s = Sub<Int>()
println(s.def(0), s.def(1)) // I'm expecting "true, false"
I understand that in order for a generic type to be initialized, it needs to conform to a protocol that contains an init() constructor. Such as...
protocol A : Equitable {
init()
}
class Sub<T : A> {
But then I would get get the error
Type 'Int' does not conform to protocol 'A'
at the line
var s = Sub<Int>()
So how would I go about making a value type such as Int or Bool conform to a protocol that can be initialized?
You need to extend Int like so for it to adopt protocol A:
class Sub<T : A> {
func def(v : T) -> Bool{
var d = T()
return d == v
}
}
protocol A : Equatable {
init()
}
extension Int: A {
}
var s = Sub<Int>()
s.def(0) // true
s.def(1)) // false

Is there an equivalent to optional chaining with arithmetic operators?

I have two optional numbers that I add. Right now it looks like this:
if let a = optionalA {
if let b = optionalB {
return a + b
}
}
return nil
For methods, there's the more convenient optional chaining syntax, like optionalA.?method syntax. Is there an equivalent for arithmetic operators that would return nil if either side was nil?
It's possible to create an operator +? that does just this like this:
infix func +?(a: Int?, b: Int?) -> Int? {
if aa = a {
if bb = b {
return aa + bb
}
}
return nil
}
but I'm wondering if there's another, built-in way to do that.
I dont think there is built in way. But you can make your own operator function:
func +(lhs: Int?, rhs: Int?) -> Int? {
if let a = lhs {
if let b = rhs {
return a + b
}
}
return nil
}
var a: Int? = 1
var b: Int? = 2
var c = a + b
Here's the custom operator approach updated for Swift 3:
infix operator +?
func +?(a: Int?, b: Int?) -> Int? {
if let aa = a, let bb = b {
return aa + bb
}
return nil
}

How to create a function that returns a generic protocol type?

In the following code, I have a generic protocol Var and it have a private implementation class LambdaVar. Now I want to have a function that return an instance of the LambdaVar without expose it publicly.
But I can't find a way to define a function that return a generic protocol type.
public protocol Var {
typealias ValueType
var value : ValueType { get }
}
struct LambdaVar<T> : Var {
let _get : Void -> T
init(_ f : Void -> T)
{
_get = f
}
var value : T {
get {
return _get()
}
}
}
public func transform<T : Var, U>(v : T, f : T.ValueType -> U) -> Var<U> {
return LambdaVar<U>() { f(v.value) } // ^^^^^^ what to put here?
}
Error:
Playground execution failed: <EXPR>:26:67: error: cannot specialize non-generic type 'Var'
public func transform<T : Var, U>(v : T, f : T.ValueType -> U) -> Var<U> {
^
<EXPR>:26:67: error: protocol 'Var' can only be used as a generic constraint because it has Self or associated type requirements
public func transform<T : Var, U>(v : T, f : T.ValueType -> U) -> Var<U> {
You should create simple wrapper type of Var like SequenceOf<T>:
struct VarOf<T>:Var {
let f:Void->T
init<V:Var where V.ValueType == T>(_ v:V) {
f = { v.value }
}
var value:T {
return f()
}
}
func transform<T : Var, U>(v : T, f : T.ValueType -> U) -> VarOf<U> {
return VarOf(LambdaVar<U>({ f(v.value) }))
}
let intVar = VarOf(LambdaVar({ 12 }))
let floatVar = transform(intVar, { Float($0) })
floatVar.value // -> 12.0

Why is generic type information lost in generic functions with a Comparable constraint?

When creating a normal generic function without constraints it works as intended, i.e:
func select<T,U>(x:T, f:(T) -> U) -> U {
return f(x)
}
The type flows through into the closure argument where it lets me access it as the strong type, i.e:
var b1:Bool = select("ABC") { $0.hasPrefix("A") }
var b2:Bool = select(10) { $0 > 0 }
It continues to work when I add an Equatable constraint:
func selectEquatable<T : Equatable, U : Equatable>(x:T, f:(T) -> U) -> U {
return f(x)
}
var b3:Bool = selectEquatable("ABC") { $0.hasPrefix("A") }
But for some reason fails when using a Comparable constraint:
func selectComparable<T : Comparable, U : Comparable>(x:T, f:(T) -> U) -> U {
return f(x)
}
var b4:Bool = selectComparable("ABC") { $0.hasPrefix("A") }
Fails with the build error:
Could not find member 'hasPrefix'
But it does allow returning itself where the type flows through as a String
var b5:String = selectComparable("ABC") { $0 }
Looking at the API docs shows that String is Comparable:
extension String : Comparable {
}
and it even allows implicit casting from a String to a Comparable:
var str:Comparable = ""
So why can't I access it as a strong-typed String inside my Closure?
var b4:Bool = selectComparable("ABC") { $0.hasPrefix("A") } //build error
It's not the String. Your closure { $0.hasPrefix("A") } has the return type Bool, which is assigned to U. Bool is Equatable, but not Comparable.
You probably want the closure to return Bool, but selectComparable to return U.
Edit
Here's evidence that returning a String (which is Comparable) instead of a Bool (not Comparable) will compile:
func selectComparable<T: Comparable, U: Comparable>(x:T, f:(T) -> U) -> U {
return f(x)
}
var b4 = selectComparable("ABC") { (str: String) -> String in str }
Your selectComparable declaration is incorrect.
func selectComparable<T: Comparable, U: Comparable>(x:T, f:(T) -> U) -> U {
return f(x)
}
U: Comparable cannot hold for type Bool, it is not Comparable, only Equatable
This will work fine
func selectComparable<T: Comparable, U>(x:T, f:(T) -> U) -> U {
return f(x)
}
as will
func select<T:Comparable,U: Equatable>(x:T, f:(T) -> U) -> U {
return f(x)
}