0

Is it possible to declare a variable of an unknown concrete type that conforms to one or more protocols?

class A: Codable {
    ...
}
class B: Codable {
    ...
}
class Serializer {
    static func serializeFromJSON<T>(type: T.Type, dict: [String:Any]) throws -> T where T: Decodable { ... }
    static func serializeToJSON<T>(_ value: T) throws -> Data where T: Encodable { ... }
}

let dict : [String:Any] = ["Someval":1] // or whatever junk data
let myObj : [???] // what goes here?
switch someval {
case a: myObj = Serializer.serializeFromJSON(type: ClassA.self, dict)
case b: myObj = Serializer.serializeFromJSON(type: ClassB.self, dict)
}
let JSONEncoder = Serializer.serializeToJSON(myObj)
Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
GoldenJoe
  • 7,874
  • 7
  • 53
  • 92
  • Why are you decoding from `[String:Any]` instead of `Data` if you are using `Decodable`? You'll need to declare that variable on a generic type to achieve your goals. – Dávid Pásztor Sep 19 '19 at 20:13
  • @DávidPásztor I have a reason but it's not relevant to the question. – GoldenJoe Sep 19 '19 at 21:02
  • @JoakimDanielson No, don't get lost in the trees. The question is about the type of `myObj` only. – GoldenJoe Sep 19 '19 at 21:02
  • 2
    @GoldenJoe in what context are you trying to declare that variable? Is it supposed to be an instance property of a type? Or just a local variable in a function? In any case, your example seem too abstract and takes away the real problem. Why would you serialize an object from JSON just so that then you can serialise it to JSON? – Dávid Pásztor Sep 19 '19 at 21:20
  • 2
    @GoldenJoe This *is entirely context specific*. Stop being so resistive to David's line of questioning, it's entirely valid. Without knowing the concrete type an object, the best you can do is hold onto it by some supertype. In your JSON case here, `let myObj: Codable` is the appropriate super type. In a contextless vacuum, `Any` is the only available super type. As the name implies, any value can be assigned to it, but it also can't do *anything*, without first casting to some more useful type. – Alexander Sep 19 '19 at 22:19
  • @Alexander NO IT IS NOT. Do you know what a concrete type is? The point is that you don’t know what concrete type it will be until you hit the switch. If you just try to make it Codable you will get an error in the last line because Codable isn’t a concrete type. – GoldenJoe Sep 19 '19 at 22:27
  • "I’m not looking for a context-specific workaround either, like declaring myObj and calling serializeToJSON in each case of the switch" This is the correct answer, as much as you don't like it. You have a concrete type, and you use it. If you have a concrete type, assign it to a broader type (to achieve the sort of "one size fits all" behaviour of `myObj` that you're looking for), then you've lost the type information (unless you add it back in later with casts, which is gross), and you no longer have a concrete type available, such as for use with `Serializer.serializeToJSON(myObj)`. – Alexander Sep 19 '19 at 22:35

0 Answers0