kennyc
(Kenny Carruthers)
1
In the example below, why can Swift not assign an explicitly type property of String or Double to a generic property of type T? However, if I use a generic constraint to specify an explicit type, then it does work?
import Foundation
class BadBox<T> {
var value: T
init(_ value: String) {
self.value = value // Cannot assign value of type 'String' to type 'T'.
}
init(_ value: Double) {
self.value = value // Cannot assign value of type 'String' to type 'T'.
}
}
class GoodBox<T> {
var value: T
init(_ value: T) where T == String {
self.value = value // This is OK and compiles fine.
}
init(_ value: T) where T == Double {
self.value = value // As does this.
}
}
It occasionally comes up that I want to define a class who's public interface explicitly defines the types of properties it can be used with, but who's internal implementation has generic components.
Creating an empty Protocol just to use as a generic constraint for such a class, ex: Boxable, seems needlessly verbose to me, though perhaps that's the Swift way?
xAlien95
(Stefano De Carolis)
2
In both BadBox<T> and GoodBox<T>, T is a generic parameter. This however doesn't mean that T can be any type. T is fixed for each instance.
The error message in the first initializer is self-explanatory: you cannot assign a value of type String to a value of type T. init(_ value: String), as defined, would be available independently of the generic parameter T and this means that the following would be allowed:
let string = "Swift"
let x = BadBox<String>(string) // uses BadBox<String>.init(_ value: String)
let y = BadBox<Double>(string) // uses BadBox<Double>.init(_ value: String)
In the first example T == String, so x.value is a String and self.value = value would be an allowed assignment.
In the second example, however, T == Double, so y.value is a Double, but you cannot assign a String value to a Double instance.
1 Like