[swift-users] still wrestling with a type conversion problem
Jacob Bandes-Storch
jtbandes at gmail.com
Tue Jul 4 00:58:29 CDT 2017
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 at 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 at swift.org
> https://lists.swift.org/mailman/listinfo/swift-users
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20170703/54efdb62/attachment.html>
More information about the swift-users
mailing list