[swift-evolution] NSCoding-like Persistence

Jonathan Hull jhull at gbis.com
Thu Mar 24 20:30:15 CDT 2016

What is the current plan for persisting things like enums and structs in Swift?

After the POP talk at WWDC, I excitedly rewrote many of my frameworks to use protocols and structs/enums instead of NSObject subclasses.  For the most part, this has been fantastic… most things are much more powerful/flexible using protocols and value types.  The one problem I keep running into, however, is how to persist things in the same way you can with NSCoding.  NSCoding requires NSObject as a base class.

I spent the last couple of weekends playing with ideas for a persistence framework and I was able to get about 90% of the way there.  I was able to encode types like [(Int,Float)] by supplying closures to the encoding function.  For example:  func encodeArray<T>(array:[T], forKey:String, mapping:(T)->Encoding).  There is a simpler version without the closure for arrays where T adheres to my “Encodable” protocol:  func encodeArray<T:Encodable>(array:[T], forKey:String).  I also have legacy support for objects which adhere to NSCoding.

Instead of going straight to data like NSCoding, I encode to an intermediate format (A struct with an internal enum).  Then you have another protocol which can turn that format into data, json, plist, etc…

90% working, but I ran into a few problems.  First, I have to use this horrible thing to get the type system to cooperate in some cases:

func horribleAutocastHack<T>(x:Any, fail:(()throws-> T)? = nil)throws -> T{
    if let cast = x as? T{
        return cast
    if let fail = fail{
        return try fail()
    fatalError("Autocast failed")

Second, I had to use static methods instead of init in my protocol, since init fails on classes where I don’t have access to the code (e.g. NSData).  It wants me to mark it both required and final, which I can’t do.

Third, I have no idea how to persist closures. It may just be flat out impossible.  The big effect it has had is that anywhere where I had to build a thunk to store a collection of heterogeneous objects (adhering to a protocol with self requirements) it can no longer be persisted.  This is actually the biggest issue, and I haven’t even been able to hack around it.

Finally, I am pushing the generics system pretty hard.  My first version was randomly crashing the compiler so I had to pull back on that front (e.g. having encodeArray instead of just encode which infers the arrayness).  All of the various discussions around factory methods are also relevant.

I was able to get the rest working though.  

Is there an official plan which I am duplicating effort on?  I would be happy to share my code (after a couple more iterations) if that would be helpful/inspiring.  I would also be happy to just work on other things and wait for the official solution if there is one coming…  I may have to wait for more powerful generics in any case.

I feel like this is one of those things that is impacting a lot of real world codebases, and delaying adoption of POP, value types, etc...


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160324/b074309b/attachment.html>

More information about the swift-evolution mailing list