Using a protocol with an "as?" cast convinces the compiler to do a dynamic lookup for a protocol conformance based on the value's actual type:
protocol MyEncodable { func encoded() -> Any } func encode<T>(_ value: T) -> Any { if let value = value as? MyEncodable { // print("Calling complex encoding for value") return value.encoded() } else { // print("Calling simple encoding for value") return value } } extension Set: MyEncodable { func encoded() -> Any { // print("Calling complex encoding for Set") return self.map { $0 } } } print(type(of: encode(3))) // Int print(type(of: encode(Set([3,4,5])))) // Array<Int> func genericEncode<T>(_ value:T) -> Any { return encode(value) } print(type(of: genericEncode(3))) // Int print(type(of: genericEncode( Set([3,4,5])))) // *Array<Int>* (You could've just used a protocol for everything, and done away with encode() as a free function, except that you can't make .encoded() work on any arbitrary type without an explicit conformance, and "extension Any: MyEncodable" isn't allowed.) -Jacob On Mon, Jul 3, 2017 at 10:44 PM, David Baraff via swift-users < swift-users@swift.org> wrote: > I’m trying to provide some custom serialization from within a generic > class. > (Briefly put, I want to automatically convert types like Set to an array > upon serialization, and the reverse when I read it back.) > > While trying things out, I was suprised by this: > > public func encode<T>(_ value:T) -> Any { > // print("Calling simple encoding for value") > return value > } > > public func encode<T>(_ value:Set<T>) -> Any { > // print("Calling complex encoding for value") > return value.map { $0 } > } > > —————————————— > > The above transforms a Set to a list, but leaves everything else alone. > As expected: > > > print(type(of: encode(3))) // Int > print(type(of: encode( Set([3,4,5])))) // Array<Int> > > Good. But now I do this: > > func genericEncode<T>(_ value:T) -> Any { > return encode(value) > } > > print(type(of: genericEncode(3))) // Int > print(type(of: genericEncode( Set([3,4,5])))) // Set<Int> > > Aha. Inside my generic function, I’ve “lost” the ability to overload > based on type. In retrospect, this is perhaps not to surprising. Still, > is there anyway that I can provide specialized versions of my functions > which will take effect when called from *within* a generic function? > > I’m basically trying to leave any type that is happy to go to/from > UserDefaults alone, but for some set of types which isn’t JSON serializable > (e.g. Set) I’d like to provide a simple pathway. I don’t aim to hit every > type in the world, but right now, I’m *totally* stymied when trying to do > the serialization from within a generic class, as I lost any ability to > specialize which function gets called. > > [I’m from the C++ world of templates and metaprogramming, and I’m shifting > from one set of constraints to another. The swift type system with > generics is cool and powerful, but man i’m still trying to really wrap my > head around it. Not that C++ was any easier…] > > > _______________________________________________ > swift-users mailing list > 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