Hello,
I'd like to have a generic struct that can be initialized with some data whose type is constrained but unknown up to the point of initialization. The motivation for this is that I have certain "value types" which can or cannot be created from raw data (i.e. AnyObject). The aforementioned struct should be initializable with raw data from which such a value type can be created. Here's the code:
protocol ValueType {
init?(raw: AnyObject)
}
struct StringValue: ValueType {
var value: String
init?(raw: AnyObject) {
guard let stringValue = raw as? String else { return nil }
self.value = stringValue
}
}
struct IntValue: ValueType {
var value: Int
init?(raw: AnyObject) {
guard let intValue = raw as? Int else { return nil }
self.value = intValue
}
}
struct ValueContainer<T: ValueType> {
var value: T
init(value: T) {
self.value = value
}
init?(raw: AnyObject) {
guard let value = T(raw: raw) else { return nil }
self.init(value: value)
}
}
With that I can create a ValueContainer instance only if I explicitly specify the type in angle brackets:
let intValueContainer = ValueContainer<IntValue>(raw: 1) // <-- works
Ideally I'd like to let the initializer figure out the type itself so I don't have to know it in advance (checking all possible types manually inside the initizlier would be ok for me), but I don't know if that's possible at all – at least I did not find a working solution. If this turns out to be impossible, e.g. because T must be known before init can be called, is there a way to make a factory method (which may live outside of ValueContainer) that implements the described behavior? I failed to find a solution for that, too.
I think the reason for why you are not able to find a solution that you are satisfied with is that you want to use generics for this even though
generics is a compile time thing, designed to be used with static types, and mixing static generics with dynamic types at runtime is rather like mixing steak and ice cream. Steak is great. Ice cream is great. Steak with ice cream is a bit unpleasant.
The above is from a talk called Zero Cost Abstractions by Airspeed Velocity (at ~ 1:40).
(I won't include the link because then this post would probably get stuck waiting for moderation for a very long time, but the talk is easy to find.)
I don't know enough about your concrete goal here, but I guess you could try to use an enum (but you probably already have), or just accept that what's knowable only at runtime can't be represented in static types / be known at compile time, thus: Model the parts that has to be dynamic/runtime just like you would in Objective-C, ie by simply using the dynamic features of the language (reference types, dynamic typing, dynamic typechecking, dynamic dispatch, runtime polymorphism, etc.).
The difference between ObjC and Swift in this regard is just that Swift adds a lot of static/compile time features, which is very nice, but it doesn't mean that you can take advantage of the static/compile time features for dynamic/runtime things. And also there's no need to recreate any (still existing) dynamic features by jumping through hoops.