JSON Parsing Reborn

If you read my previous piece on JSON Parsing in Swift, things looked really drab. And in fact, if you try to use Swift straight-up to do it, it still sucks. However, while trying to make this experience better, I stumbled across one very interesting feature of Swift that helped me create a very light-weight JSON library that gives me all of the expressiveness I had with ObjC while keeping true to the semantics of Swift.

In ObjC, we are able to express JSON as a literal construct made up of the various Foundation types. There was a land-mine waiting if you didn't use the right types, such as NSData, with properly encoding them first, but it was possible to do and the syntax was great. In Swift, a semantic JSON blob might look like this:

var json = [
  "stat": "ok",
  "blogs": [
    "blog": [
      [
        "id" : 73,
        "name" : "Bloxus test",
        "needspassword" : true,
        "url" : "http://remote.bloxus.com/"
      ],
      [
        "id" : 74,
        "name" : "Manila Test",
        "needspassword" : false,
        "url" : "http://flickrtest1.userland.com/"
      ]
    ]
  ]
]

That is semantically what we want and Swift will happily allow us to shove that into an NSDictionary or Dictionary<String, AnyObject>. My fear was that creating a "real" version of this in Swift would require manually boxing the types, and that sucks! And then I stumbled upon a truly awesome feature of Swift. Seriously, it's sweet!

Introducing Convertibles

Convertibles allow you to specify ways to convert most of the literals into a different type by implementing a protocol. Let's take a look at an example:

class MyDoubleDouble : FloatLiteralConvertible {
    var double : Double

    init(_ value: Double) {
        double = value * 2
    }

    class func convertFromFloatLiteral(value: Double) -> MyDoubleDouble {
        return MyDoubleDouble(value)
    }
}

let double = 2.0                        // double has a value of 2.0
let myDouble : MyDoubleDouble = 2.0     // myDouble.double has a value of 4.0

Ok. Things just got really interesting now. We can extend this to nearly all of the literal types, including dictionaries and arrays. So we can actually keep the terse and expressive syntax from above if we simply annotate the type for the JSON value:

var json : JSON = [ ... ]

With that one type annotation of JSON (defined in my library), that code gets created in a fully type-safe JSON structure. That is pure gold.

Indexing the Goods

Retrieving the data from within the JSON is just as easy as well. If we overload the subscript methods for strings and integers, we can provide full dictionary and array lookups that are type-safe and conform to the semantics of Swift's optional typing.

A quick example of grabbing the blog ID from the first blog in the structure.

if let blogId = json["blogs"]?["blog"]?[0]?["id"]?.number {
  println("blog ID: \(blogID)")
}

In The End

With just a little bit of work (and a lot of time fighting with current bugs in Xcode and Swift), Swift makes it possible to toe the line between type-safety and expressiveness. I can only imagine, that when we get proper documentation for all of this goodness, that most of my static typing concerns will simply dissapear.

Feeling much more bullish on Swift today. =)

Full Source for the JSON project is here: https://github.com/owensd/json-swift/.

JSON Parsing Reborn