Type "T?" does not conform to protocol 'Equatable'


(Rudolf Adamkovič) #1

Hi everyone!

I have a generic class similar to this one:

class C<T: Equatable> {
    let t: T
    init(t: T) { self.t = t }
}

When try to wrap ‘Int?' inside, I get the following error:

let a = C<Int?>(t: nil) // ERROR: Type "Int?" does not conform to protocol 'Equatable'

Yet when I try to compare two ‘Int?’ values, everything works:

let a: Int? = 5
let b: Int? = 6

let c = a == b // NO ERROR

So, is ‘Int?' equatable or not?

Thanks!

R+


(Keith Duvall) #2

Don’t mark it as optional in the generic definition. Mark it as optional in your implementation.

class C<T: Equatable> {
  let t: T?
  init(t: T?) {
    self.t = t
  }
}

let a = C<Int>(t: nil)

print(a.t) // nil

let b = C<Int>(t: 5)

print(b.t) // Optional(5)

Keith

···

On Feb 29, 2016, at 9:24 AM, Rudolf Adamkovič via swift-users <swift-users@swift.org> wrote:

Hi everyone!

I have a generic class similar to this one:

class C<T: Equatable> {
    let t: T
    init(t: T) { self.t = t }
}

When try to wrap ‘Int?' inside, I get the following error:

let a = C<Int?>(t: nil) // ERROR: Type "Int?" does not conform to protocol 'Equatable'

Yet when I try to compare two ‘Int?’ values, everything works:

let a: Int? = 5
let b: Int? = 6

let c = a == b // NO ERROR

So, is ‘Int?' equatable or not?

Thanks!

R+
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Chris McIntyre) #3

Int? is not Equatable, b. You would have to use a non-optional.

Under the hood, Optionals are actually an Enum with two cases, None, and Some<T>. func ==(lhs: Int?, rhs: Int?) must be designed essentially as a switch statement to handle each possibility.

···

--
Chris McIntyre

On Feb 29, 2016, at 9:24 AM, Rudolf Adamkovič via swift-users <swift-users@swift.org> wrote:

Hi everyone!

I have a generic class similar to this one:

class C<T: Equatable> {
    let t: T
    init(t: T) { self.t = t }
}

When try to wrap ‘Int?' inside, I get the following error:

let a = C<Int?>(t: nil) // ERROR: Type "Int?" does not conform to protocol 'Equatable'

Yet when I try to compare two ‘Int?’ values, everything works:

let a: Int? = 5
let b: Int? = 6

let c = a == b // NO ERROR

So, is ‘Int?' equatable or not?

Thanks!

R+
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Peter Vertes) #4

To extend on Keith’s explanation:

class C<T: Equatable> {
    let t: T?
    init(t: T?) { self.t = t }
}

let a = C<Int>(t: nil)
print(a.t)

let b = C<Int>(t: 5)
print(b.t)

let c = C<Int>(t: 5)
print(c.t)

func ==(lhs: C<Int>, rhs: C<Int>) -> Bool {
    return lhs.t == rhs.t
}

var d = a == b // false
var e = b == c // true

You’d also need to override the “==“ operator for C<Int> types in order to be able to compare them.

-Pete

···

On Feb 29, 2016, at 10:07 AM, Keith Duvall via swift-users <swift-users@swift.org> wrote:

Don’t mark it as optional in the generic definition. Mark it as optional in your implementation.

class C<T: Equatable> {
  let t: T?
  init(t: T?) {
    self.t = t
  }
}

let a = C<Int>(t: nil)

print(a.t) // nil

let b = C<Int>(t: 5)

print(b.t) // Optional(5)

Keith

On Feb 29, 2016, at 9:24 AM, Rudolf Adamkovič via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

Hi everyone!

I have a generic class similar to this one:

class C<T: Equatable> {
    let t: T
    init(t: T) { self.t = t }
}

When try to wrap ‘Int?' inside, I get the following error:

let a = C<Int?>(t: nil) // ERROR: Type "Int?" does not conform to protocol 'Equatable'

Yet when I try to compare two ‘Int?’ values, everything works:

let a: Int? = 5
let b: Int? = 6

let c = a == b // NO ERROR

So, is ‘Int?' equatable or not?

Thanks!

R+
_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(David Sweeris) #5

To the best of my understanding, Int? is not equatable. Your let c = a == b code works because this function (or something like it) is defined:
func == <T: Equatable> (lhs: Optional<T>, rhs: Optional<T>) -> Bool {
    switch (lhs, rhs) {
    case (.None, .None): return true
    case (.Some(let l), .Some(let r)): return l == r
    default: return false
    }
}

The reason it’s done this way is that currently there’s no mechanism for conditional protocol conformance. Ideally, you’d be able to write something like this:
extension Optional : Equatable where T: Equatable {}
… which, combined with that existing == function, would make Int? be equatable.

IIRC, Apple is intending to remove this limitation, but I can’t remember if it’s made the cut for Swift 3 or if it’ll be later on.

In the meantime, if Keith’s solution of making the variable be a T? instead of T doesn’t work for you, I think this will let you continue on with other parts of your code (although I have NOT thoroughly tested it… use at your own risk):
public struct OptionalWrapper<T> : Equatable {
    typealias Wrapped = T
    var unwrap: Wrapped?
    init(_ value: Wrapped?) { unwrap = value }
}
public func == <T: Equatable> (lhs: OptionalWrapper<T>, rhs: OptionalWrapper<T>) -> Bool {
    switch (lhs.unwrap, rhs.unwrap) {
    case (.None, .None): return true
    case (.Some(let l), .Some(let r)): return l == r
    default: return false
    }
}
public func == <T: Equatable> (lhs: OptionalWrapper<T?>, rhs: OptionalWrapper<T?>) -> Bool {
    switch (lhs.unwrap, rhs.unwrap) {
    case (.None, .None): return true
    case (.Some(let l), .Some(let r)): return l == r
    default: return false
    }
}
public func == <T> (lhs: OptionalWrapper<T>, rhs: OptionalWrapper<T>) -> Bool {
    switch (lhs.unwrap, rhs.unwrap) {
    case (.None, .None): return true
    case (.Some, .None): return false
    case (.None, .Some): return false
    case (.Some, .Some): fatalError("\(__FILE__):\(__LINE__):\(__COLUMN__): Binary operator '==' cannot be applied to two '\(T.self)' operands")
    }
}

The syntax for actually using it is a bit long, but it should work:
let a = C(t: OptionalWrapper(4)) // infers that Wrapped == Int
let b = C(t: OptionalWrapper<Int>(nil)) // must be explicit since nil is just Optional.None, without any other type info
let c = a.t == b.t // false

Hope that helps

- Dave Sweeris

···

On Feb 29, 2016, at 8:24 AM, Rudolf Adamkovič via swift-users <swift-users@swift.org> wrote:

Hi everyone!

I have a generic class similar to this one:

class C<T: Equatable> {
    let t: T
    init(t: T) { self.t = t }
}

When try to wrap ‘Int?' inside, I get the following error:

let a = C<Int?>(t: nil) // ERROR: Type "Int?" does not conform to protocol 'Equatable'

Yet when I try to compare two ‘Int?’ values, everything works:

let a: Int? = 5
let b: Int? = 6

let c = a == b // NO ERROR

So, is ‘Int?' equatable or not?

Thanks!

R+
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Rudolf Adamkovič) #6

Hi everyone!

I have a generic class similar to this one:

class C<T: Equatable> {
    let t: T
    init(t: T) { self.t = t }
}

When try to wrap ‘Int?' inside, I get the following error:

let a = C<Int?>(t: nil) // ERROR: Type "Int?" does not conform to protocol 'Equatable'

Yet when I try to compare two ‘Int?’ values, everything works:

let a: Int? = 5
let b: Int? = 6

let c = a == b // NO ERROR

So, is ‘Int?' equatable or not?

Thanks!

R+


(Rudolf Adamkovič) #7

Got it. Thanks!

R+

···

On 29 Feb 2016, at 16:07, Keith Duvall via swift-users <swift-users@swift.org> wrote:

Don’t mark it as optional in the generic definition. Mark it as optional in your implementation.

class C<T: Equatable> {
  let t: T?
  init(t: T?) {
    self.t = t
  }
}

let a = C<Int>(t: nil)

print(a.t) // nil

let b = C<Int>(t: 5)

print(b.t) // Optional(5)

Keith

On Feb 29, 2016, at 9:24 AM, Rudolf Adamkovič via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

Hi everyone!

I have a generic class similar to this one:

class C<T: Equatable> {
    let t: T
    init(t: T) { self.t = t }
}

When try to wrap ‘Int?' inside, I get the following error:

let a = C<Int?>(t: nil) // ERROR: Type "Int?" does not conform to protocol 'Equatable'

Yet when I try to compare two ‘Int?’ values, everything works:

let a: Int? = 5
let b: Int? = 6

let c = a == b // NO ERROR

So, is ‘Int?' equatable or not?

Thanks!

R+
_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Rudolf Adamkovič) #8

Wow! Thanks for (extra-extra-extra) detailed answer. I will try this.

R+

···

On 29 Feb 2016, at 17:41, davesweeris@mac.com wrote:

To the best of my understanding, Int? is not equatable. Your let c = a == b code works because this function (or something like it) is defined:
func == <T: Equatable> (lhs: Optional<T>, rhs: Optional<T>) -> Bool {
    switch (lhs, rhs) {
    case (.None, .None): return true
    case (.Some(let l), .Some(let r)): return l == r
    default: return false
    }
}

The reason it’s done this way is that currently there’s no mechanism for conditional protocol conformance. Ideally, you’d be able to write something like this:
extension Optional : Equatable where T: Equatable {}
… which, combined with that existing == function, would make Int? be equatable.

IIRC, Apple is intending to remove this limitation, but I can’t remember if it’s made the cut for Swift 3 or if it’ll be later on.

In the meantime, if Keith’s solution of making the variable be a T? instead of T doesn’t work for you, I think this will let you continue on with other parts of your code (although I have NOT thoroughly tested it… use at your own risk):
public struct OptionalWrapper<T> : Equatable {
    typealias Wrapped = T
    var unwrap: Wrapped?
    init(_ value: Wrapped?) { unwrap = value }
}
public func == <T: Equatable> (lhs: OptionalWrapper<T>, rhs: OptionalWrapper<T>) -> Bool {
    switch (lhs.unwrap, rhs.unwrap) {
    case (.None, .None): return true
    case (.Some(let l), .Some(let r)): return l == r
    default: return false
    }
}
public func == <T: Equatable> (lhs: OptionalWrapper<T?>, rhs: OptionalWrapper<T?>) -> Bool {
    switch (lhs.unwrap, rhs.unwrap) {
    case (.None, .None): return true
    case (.Some(let l), .Some(let r)): return l == r
    default: return false
    }
}
public func == <T> (lhs: OptionalWrapper<T>, rhs: OptionalWrapper<T>) -> Bool {
    switch (lhs.unwrap, rhs.unwrap) {
    case (.None, .None): return true
    case (.Some, .None): return false
    case (.None, .Some): return false
    case (.Some, .Some): fatalError("\(__FILE__):\(__LINE__):\(__COLUMN__): Binary operator '==' cannot be applied to two '\(T.self)' operands")
    }
}

The syntax for actually using it is a bit long, but it should work:
let a = C(t: OptionalWrapper(4)) // infers that Wrapped == Int
let b = C(t: OptionalWrapper<Int>(nil)) // must be explicit since nil is just Optional.None, without any other type info
let c = a.t == b.t // false

Hope that helps

- Dave Sweeris

On Feb 29, 2016, at 8:24 AM, Rudolf Adamkovič via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

Hi everyone!

I have a generic class similar to this one:

class C<T: Equatable> {
    let t: T
    init(t: T) { self.t = t }
}

When try to wrap ‘Int?' inside, I get the following error:

let a = C<Int?>(t: nil) // ERROR: Type "Int?" does not conform to protocol 'Equatable'

Yet when I try to compare two ‘Int?’ values, everything works:

let a: Int? = 5
let b: Int? = 6

let c = a == b // NO ERROR

So, is ‘Int?' equatable or not?

Thanks!

R+
_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users