Swift and Inheritance

When looking at how to design and structure our own code, it's often best to start with what exists in the language and platform that we are working in. So, when it's time to design a new type, such as a SortedArray or Set, how would we implement this in Swift?

I'm guessing that your first thought is to inherit the Array class and override the insertion methods and indexing setter (unless you're already familiar with Swift…). However, that will not work because the Array class in Swift is not a class at all, it is a struct. There has been much discussion about this on the developer forums and I also wrote about some of my concerns with them already, but most of that was with the broken semantics of arrays with the let construct; I did not see much in the context of the problems with extensibility.

There is a good argument that this is bad example as the APIs are slightly different between an Array and a Set class, but the metapoint still stands.

: .info

If we look at the Swift documentation, this is what we learn about structs, or rather, the benefits of classes over structs:

Classes have additional capabilities that structures do not:

  • Inheritance enables one class to inherit the characteristics of another.
  • Type casting enables you to check and interpret the type of a class instance at runtime.
  • Deinitializers enable an instance of a class to free up any resources it has assigned.
  • Reference counting allows more than one reference to a class instance.

I've bolded the part that is going to limit us in our design choices. We really only have two options available to us now:

  1. Composition 2. A new implementation

Neither of these approaches is ideal because they require significantly more code than the inheritance choice we should have had.

This goes back to my original thoughts on Swift and one of the foundational aspects of Objective-C: extensibility. When I referenced that, I was not talking about the extensibility of the ObjC language, but rather, the extensibility of every type in the system.

Swift, at it's heart, seems to be going against that at fundamental level. The two biggest pieces of evidence for this are the the following:

  1. Every type we have seen thus far in the Swift Standard Library has been declared as a struct. Interestingly enough, many are also backed by internal class types. 2. The introduction of the @final construct to specifically prevent inheritance and extending the functionality of class types

So what is the take-away when foundational types of the language that are classic examples of types that should be classes are implemented as structs? To me, it seems the API designers for Swift are already compensating for weaknesses in the language's runtime and are trading supposed run-time performance over platform extensibility and that we, as developers of frameworks, should be doing the same.

Swift and Inheritance

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

JSON Parsing

Update June 21st: I've fixed the errors of my ways: JSON Parsing Reborn. The content of this article still holds if you use straight-up Swift, but Swift provides us with a much better way to improve this.

: .info

In my previous article, I got some flack about many things, including JSON parsing and how the Swift code is no worse because of the generics. Here's an example of why I think it is worse. If any of the code is incorrect or if it could be written better, let me know and I'll update accordingly. Maybe I'll be proven wrong and that I just need to do it a different way and the problems go away. If that's the case, that would great.

Here is the JSON that we will be parsing:

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

Both the ObjC code and the Swift code works under the following conditions (that is, it prints nothing when invalid or prints the blog entries when valid; also, it does not crash):

  1. The JSON response is nil
  2. The JSON response is an unexpected type, such as an array or string
  3. The JSON response does not have the blogs key
  4. The JSON response has the blogs key, but not the blog key
  5. The JSON response has the keys, but blog is the wrong type
  6. The JSON response has the keys and correct type, but blog is empty
  7. The JSON response has the keys, the correct types, and data in blog, but missing some keys (such as id or name)
  8. The JSON response is fully filled out

Here is the ObjC code that is needed to safely parse the code:

if ([json isKindOfClass:[NSDictionary class]]) {
    NSDictionary *dict = json[@"blogs"];
    if ([dict isKindOfClass:[NSDictionary class]]) {
        NSArray *blogs = dict[@"blogs"][@"blog"];
        if ([blogs isKindOfClass:[NSArray class]]) {
            for (NSDictionary *blog in blogs) {
                if ([blog isKindOfClass:[NSDictionary class]]) {
                    NSLog(@"Blog ID: %@", blog[@"id"]);
                    NSLog(@"Blog Name: %@", blog[@"name"]);
                    NSLog(@"Blog Needs Password: %@", blog[@"needspassword"]);
                    NSLog(@"Blog URL: %@", blog[@"url"]);
                }
            }
        }
    }
}

Here is the Swift code to do the same.

if let dict = json as? NSDictionary {
    if let blogs = dict["blogs"] as? Dictionary<String, AnyObject> {
        if let blogItems : AnyObject = blogs["blog"] {
            if let collection = blogItems as? Array<AnyObject> {
                for blog : AnyObject in collection {
                    if let blogInfo = blog as? Dictionary<String, AnyObject> {
                        let id : AnyObject? = blogInfo["id"]
                        let name : AnyObject? = blogInfo["name"]
                        let needspassword : AnyObject? = blogInfo["needspassword"]
                        let url : AnyObject? = blogInfo["url"]

                        println("Blog ID: \(id)")
                        println("Blog Name: \(name)")
                        println("Blog Needs Password: \(needspassword)")
                        println("Blog URL: \(url)")
                    }
                }
            }
        }
    }
}

I wrote unit tests for both Swift and ObjC to validate the claims I made above; both sets of code run without crashing under the error conditions and print the output successfully.

Both sets of code have to do similar checks to validate the types, but the Swift code is cluttered with meaningless type annotations. Also, the retrieval of items out of the dictionaries seems more complicated than it needs to be. Maybe I'm simply doing something wrong…

Of course, this isn't the canonical use of JSON. Really, the ObjC version of the code should actually boil down to this:

for (NSDictionary *blog in json[@"blogs"][@"blog"]) {
  NSLog(@"Blog ID: %@", blog[@"id"]);
  NSLog(@"Blog Name: %@", blog[@"name"]);
  NSLog(@"Blog Needs Password: %@", blog[@"needspassword"]);
  NSLog(@"Blog URL: %@", blog[@"url"]);
}

Why? Simple: when dealing with JSON, the structure is well-defined as we are simply parsing out the results.

The simplest I could get the Swift code was this:

let dict = json as Dictionary<String, AnyObject>
let blogs : AnyObject? = dict["blogs"]?["blog"]
let collection = blogs! as Array<Dictionary<String, AnyObject>>
for blog in collection {
  let id : AnyObject? = blog["id"]
  let name : AnyObject? = blog["name"]
  let needspassword : AnyObject? = blog["needspassword"]
  let url : AnyObject? = blog["url"]

  println("Blog ID: \(id)")
  println("Blog Name: \(name)")
  println("Blog Needs Password: \(needspassword)")
  println("Blog URL: \(url)")
}

All of the type gymnastics is off-putting, especially since it conveys no meaning and reduces the clarity of the code significantly. The bigger the JSON blob to parse, the more this issue is exasperated.

Note that you need AnyObject? to remove the compiler warnings.

Update: June 18th

I was asked on twitter by @jtjoelson why I didn't use typed dictionaries if I knew the schema. Well, I didn't think it helped the code. Here are two versions using fully typed information based on the JSON schema.

let dict = json as Dictionary<String, Dictionary<String, Array<Dictionary<String, AnyObject>>>>
let blogs = dict["blogs"]!["blog"]!
for blog in blogs {
  let id : AnyObject? = blog["id"]
  let name : AnyObject? = blog["name"]
  let needspassword : AnyObject? = blog["needspassword"]
  let url : AnyObject? = blog["url"]

  println("Blog ID: \(id)")
  println("Blog Name: \(name)")
  println("Blog Needs Password: \(needspassword)")
  println("Blog URL: \(url)")
}

Of course, we can make that monster of a type look better with typealiases.

typealias Blog = Dictionary<String, AnyObject>
typealias BlogCollection = Array<Blog>
typealias BlogsDictionary = Dictionary<String, BlogCollection>
typealias FlickrResponse = Dictionary<String, BlogsDictionary>

let dict = json as FlickrResponse
let blogs = dict["blogs"]!["blog"]!
for blog in blogs {
  let id : AnyObject? = blog["id"]
  let name : AnyObject? = blog["name"]
  let needspassword : AnyObject? = blog["needspassword"]
  let url : AnyObject? = blog["url"]

  println("Blog ID: \(id)")
  println("Blog Name: \(name)")
  println("Blog Needs Password: \(needspassword)")
  println("Blog URL: \(url)")
}

The type information is certainly more legiable. But really, the only choice from here to make this more readable and filled with less type info is to create classes to represent all of this and parse the values yourself. That's a lot of code to write for very little value.

The ObjC code will throw an exception if the schema is invalid. I can catch that exception and log it, but there is little error recovery that I can really do at the point. The rigid class will have to ultimately do the same thing, or report an error status of some kind. In ObjC, I had to write far less code and more readable code than I did in Swift to arrive at the same outcome: failed parsing or correct output.

JSON Parsing

Is Swift Really ObjC without the C?

It has only been weeks since Swift was announced, and it is only the first drop of Swift that the public has seen. At the same time, we are only a matter of months away from the nebulous "Fall" timeframe for when the Swift language will essentially hit v1.0 with the final drop of Xcode 6.

This has me very sad for the future of iOS and OS X development. I do not see, at this point in time, any major changes happening to Swift. There are many fundamental items about Swift that I'm just not a fan of and I think break the spirit of what ObjC was about: pragmatism.

These are the items that I think truly represent the heart of ObjC:

  1. Dynamic Typing
  2. Message Passing
  3. Extensibility (at runtime)
  4. Protocols (aka Interfaces)

The rest of the features of ObjC are really just implemented on these ideals. With the advent of Swift, we see these as the ideals:

  1. Static Typing 2. Generics 3. Dispatch tables 4. Extensibility (at compile time)

Gone is the dynamic nature of ObjC; it has instead been replaced by a rigid, generic based type system. I know the world of C

I do not think we got "ObjC without the C", rather, we got something much more like C# that compiles on clang and bridges into Cocoa a bit haphazardly.

ObjC without the C

I'm going to break down some examples of what I would have liked to have seen in Swift instead of what we got; I'll refer to that version of Swift as SwiftOC (or Swift with ObjC).

Generics

Let's start off with everyone's favorite canonical example of why we need generics: a collection of items.

In Swift, we can create strongly-typed collections:

let intArray = [1, 2, 3, 4]        // Array<Int>
let stringArray = [ "hi", "bye" ]  // Array<String>
let array = [ 3, 4.5, 8.9 ]        // NSArray, not! Array<Double>

Ok, in our imagined SwiftOC, we could have had the same code, but each type would have simply been an Array:

let intArray = [1, 2, 3, 4]        // Array
let stringArray = [ "hi", "bye" ]  // Array
let array = [ 3, 4.5, 8.9 ]        // Array

But what if I put in a wrong type? I hear this argument a lot… and well, yes, it is a possibility. It is also the possibility to put in an incorrect value, to be off by one iterating over the array, or to print the contents of the wrong array; there's a line somewhere that needs to be drawn where the programmer needs to figure out how to address potential issues in ones code. However, this is a case that is immediately found at run-time; it is not a pandemic problem that needs the rigidity of generics to solve.

What about the generic functions like sort?

func sort<T : Comparable>(array: T[]) -> T[]
func sort<T>(array: T[], pred: (T, T) -> Bool) -> T[]

That is what sort looks like today. Notice a truism about generics that often gets overlooked: all generics require a contract for the types to work; sometimes this is explicit, other times it's implicit and only inferred at compile time. It is also easy to overlook the fact that this contract is often implemented via overloaded operators, which hides the details away making it look like you get certain functionality for free—I call this "compiler magic".

In SwiftOC sort would have looked like this:

// Comp would be a Comparable interface, shortened for space reasons
func sort(array: Array) -> Array
func sort(array: Array, pred: (Comp, Comp) -> Bool) -> Array

I'll admit, there is a difference between the SwiftOC code, and, yes, the Swift version is technically more type-safe, on paper at least. The difference is that in Swift you can guarantee that each item in the array adheres to the Comparable protocol.

This is where theory and practice comes in to play though. This is fundamentally not a real-world problem that gets exposed for any length of time, if at all; it is caught early, even in a project with little-to-no testing. It's a classic compile-time vs run-time tradeoff.

Further, you could actually still implement this in a collection class if you wanted by enforcing the add methods to require the inserted items to implement Comparable.

class Array {
  func insert(#item: Comparable, atIndex: Int) {}
}

There you go, all items that go into the array meet the requirements of sort. In fact, you could require and provide a default behavior for all types within the language and provide default behaviors for particular types. This again would alleviate most of the problems that were trying to be solved with generics in the above example.

Yes, generics can be useful in particular cases. However, they are not helpful, ironically, in the generic use case. I would argue that simply sticking with a stronger-type base instead of fully type-safe and generic based language would have been a more pragmatic route to take.

Let's take a look at another example where generics really are not helpful: JSON.

var resp = {
  "stat": "ok",
  "blogs": {
    "blog": [
      {
        "id" : 73,
        "name" : "Bloxus test",
        "needspassword" : 0,
        "url" : "http://remote.bloxus.com/"
      },
      {
        "id" : 74,
        "name" : "Manila Test",
        "needspassword" : 1,
        "url" : "http://flickrtest1.userland.com/"
      }
    ]
  }
}

That's a real-world JSON response from a web-services API. Note the mix of strings and numbers; even if they were all strings, they are only string representations of a number.

Swift's type-safety mechanics offer absolutely no help here. In fact, we really need to use the Cocoa types to do anything useful with this because what we have is an untyped dictionary: Dictionary<String, AnyObject!> or NSDictionary. In order to write safe code here, you have to do the exact same thing in either language: check for a null value and check for a value that can be converted to the expected type.

let blogs = resp["blogs"]?["blog"]  // ? could be done in both Swift
                                    // and SwiftOC

At the end of the day, there are essentially two worlds of programming languages when it comes to types: static and dynamic. The Apple platform and the entire web platform have run on dynamic code with relatively little problems because of the type system. However, in one move, I believe Apple did the biggest disservice to ObjC programmers: fundamentally shifted them from a world of flexibility to a world of rigidity based on the guise of "safety" and generic programming.

Simplicity

ObjC was a fairly simple language—it added on a few, well defined mechanics of top of already concise language: C. There were virtually no special rules to apply to different parts of the language. However, with Swift, we are opened up to the world of complexity. Yes, the syntax is concise and fairly easy to grasp, however, you are entering a world that is deceptively simple.

let optval : Bool? = false
if optval           { "1" }
if optval!          { "2" }
if optval == false  { "3" }
if optval! == false { "4" }
if optval == true   { "5" }
if optval! == true  { "6" }

What happens in the above code? Yes, this is a trick question and a source of some discussion on the developer forums. The answer is this:

"1"
"3"
"4"

The reason? Well, optional values can be implicitly compared to non-optional values thanks to this overloaded operator:

func ==<T : Equatable>(lhs: T?, rhs: T?) -> Bool

So that check to see if your optional value has a value or not better not use the == operator; if so, you'll end up with the wrong results. This is extremely error prone and very hard to track down because you cannot actually debug the flow to understand what is going on here; these are compiler choices not run-time decisions you can see on the stack—more "compiler magic".

Operator overloading is often cited as a powerful, if not good, addition to any language. However, it can be the source of some of the most non-obvious programming errors and is far worse then non-generic typed arrays. When the incorrect values show up in the array, things go boom quick. When these types of errors happen, they are subtle, sporadic, and often hard to repro without the exact set of data that went into the failing code path.

Let's look at another:

var intValue = 2
var doubleValue = 1.1

func add(x: Int, y: Int) -> Int { ... }
func add(x: Double, y: Double) -> Double { ... }

add(intValue, doubleValue)

Which function gets called?

If you answered, neither, you are correct! Because of Swift's type-safety, neither of these are valid. This could be a good thing such that no numbers are coerced improperly to different types, but pragmatically, this results in code that should look like this:

let radius = 4
let pi = 3.14159
var area = pi * radius * radius

Into code that looks like this:

let radius = 4
let pi = 3.14159
var area = pi * Double(radius) * Double(radius)

That's not simpler and I would argue adds no safety, but rather, detracts from what the code is supposed to really be doing. Sure radius could have been a double, but it's not always the case that one is performing math operations on the same types of values.

Also in the above is method overloading. This is relatively safe, but does promote the loss of intention from the functions. If we had:

func add(x: Int, y: Int) -> Int { ... }
func add(s1: String, s2: String) -> String { ... }
// the operator version
func +(x: Int, y: Int) -> Int { ... }
func +(s1: String, s2: String) -> String { ... }

What is the string version supposed to do? Parse the numbers from the string and return string representation of the result? Append the string? It would be much clearer to instead choose better names:

func append(string: String, to: String) -> String { ... }

This is much clearer, especially since the named parameters are part of the signature. Swift seems to be moving away from this though, especially in the context of items like overloading operators. I do not think that is a good thing. It's also against part of what has made Cocoa such a good framework to work with: self documenting code.

Syntax and Style

This is an area that I think Swift did a fairly decent job on. It's cleaner, in most cases more straight-forward, and offers some helpful shortcuts for various patterns.

There is one thing that I would have actually like Swift to address: curly braces.

Curly braces have long been the source of discussions, or rather, "holy wars". What line do they belong on, which level of indentation do they get, do we use them for one-liners? Swift had a perfect opportunity to absolve this problem by simply removing them from the language. The truth of the matter is that we simply do not need them anymore. Also, it would have imposed a style on the language that would have enforced consistently across codebases which would have only increased readability and pattern matching.

func compare(x: Int, y: Int) -> Int {
  if x < y { return -1 }
  else if x > y
  {
    return 1
  }
  else
    {
    return 0
    }
}

That's the kind of mixture of braces that we've all seen. And sometimes in the same code file! YUCK! I think Swift would have gained a lot if it took a page out of Python's book:

func compare(x: Int, y: Int) -> Int
  if x < y
    return -1
  elseif x > y
    return 1
  else
    return 0
  end
end

Sure, the end keywords are not actually necessary for a parser. However, they provide visual clarity to the end of blocks. Whitespace does an insufficient job at this, especially when scanning code quickly. But if we want to be purists, then we would have this:

func compare(x: Int, y: Int) -> Int
  if x < y
    return -1
  elseif x > y
    return 1
  else
    return 0

Of course, both should not be supported. I do think that either one would have been preferable though.

Summary

I think there is a lot more to discuss about the language and how I think Apple has missed the mark of "Objective-C without the C". Instead, it really fells like we got a form of C# 2.0 or the core of the C

Unfortunately, I do not think that much of this will change with later drops. Instead, we'll see bug fixes and refinements of what exists today. It is very un-Apple to drop such a huge and fundamentally different change on our laps as they have been the company of evolutionary refinement.

There is no doubt in my mind that Swift will win over many, but will they be from the long-time Apple developer crowd or will they be the converts from the Android and Windows world? ObjC has long been a misunderstood language to them because many were unwilling to really embrace the paradigm. Apple seems to have bent to their will instead of providing us with a truly great ObjC 3.0. This saddens me greatly.

Chris Lattner (@clattner_llvm, the guy behind the Swift language), said this about the language on Twitter:

Swift is a pragmatic, not a religious, language. It tries to get the defaults right, but allows you to change them if it doesn't suit you.

: .quote

I have to wonder, what is the pragmatic goal of Swift? From where I sit, it's gets all of the defaults wrong because the defaults should have been about the interaction with the Cocoa API. Until there are native Swift versions of those, all of code looks and feels much messier and far less elegant than what we have today.

Is Swift Really ObjC without the C?

Problematic Swift Arrays

In the Apple developer forums, there is a lot of talk about how the semantics of arrays are messed up in the current beta builds of Xcode 6. Yes, they are messed up, but many are missing the actual problem and are trying to solve the symptoms.

Example issue with arrays:

let array = [5, 1, 0, 10]
array[1] = 0  // just changed a value in the "const" array, ok...
array += 5    // compile time error: good

var sortedArray = sort(array) // original array updated, oops!
sortedArray.append(4)

sortedArray   // prints: [0, 0, 5, 10, 4]
array         // prints: [0, 0, 5, 10]

Ok, we can hopefully see a series of errors here.

  1. Constant arrays can have their positional values changed, but not appended to 2. Arrays that were constant in one function scope are indeed not constant when passed to another function

So what's the real problem here? There are actually two problems that end up causing this issue:

  1. Arrays are structs and structs have value-type semantics. The entire metadata for the array, such as the startIndex, endIndex, and the array buffer pointer all get copied on assignment. This is ripe for bugs, as we have seen above. 2. Lack of true immutable types.

I'm going to assert that issue #2 is the true source of the problem. Let's look at the example above but change two assertions about the language:

  1. Classes have the same mutating attribute that can be applied to them as structs. 2. All parameters into functions are immutable unless the inout attribute is specified.

First, the basic definition of the array looks like this:

struct Array<T> {
  var startIndex : Int, endIndex : Int
  var buffer : ArrayBuffer<T>
}

It's important to note that the ArrayBuffer is essentially a class (technically it's a struct, but internally it uses a class to store the contents of the array).

When a copy of the array is made, all of the values of the array get copied; that is:

  1. The numerical value of startIndex 2. The numerical value of endIndex 3. The pointer to the array buffer, not the contents of the array

Let's take a look at a simple function to reverse an array:

func reverseArray<T>(array : T[]) -> T[] {
  var copy = array.copy()
  var left = 0, right = array.endIndex - 1
  while left < right {
    var swap = copy[left]
    copy[left] = copy[right]
    copy[right] = swap
    left++; right--
  }
  return copy
}

Now, this method works correctly with today's implementation Swift. It works because of the bolded line: it creates a deep-copy of the array and not just a copy of the pointer to the array contents.

If I wrote the function as such:

func reverseArray<T>(array : T[]) -> T[] {
  var copy = array
  var left = 0, right = array.endIndex - 1
  while left < right {
    var swap = copy[left]
    array[left] = copy[right]
    copy[right] = swap
    left++; right--
  }
  return copy
}

This method now suffers from the problem of updating the array that is being passed in (I also introduce another bug on line 6 to show the other failure case). This is the real problem!

Now, if the Swift language implemented the two items I mentioned above, the above function would not have compiled. Instead, the following would be true:

  1. Line 2 would have a compiler error for assigning an immutable type to a mutable type (remember, I claim that parameters should be immutable by default, only overridden by the inout attribute) 2. Line 6 would also have a compiler error because the subscript methods would have needed to be marked with mutating in order for assignment to take place.

The problem is not with arrays in Swift; the problem is in how Swift does not have a mechanism to stop classes from mutating its members.

I'll leave you with this one last example, put it in your playground and you'll see immediately that arrays are just a specific example of this limitation:

class CPerson {
  var name : String
  init(name : String) { self.name = name }
}

struct SPerson {
  var age : Int
  var person : CPerson
  mutating func haveBirthday() {
    println("Happy birthday!")
    age++
  }
}
let david = SPerson(age: 32, person: CPerson(name: "David"))
var frank = SPerson(age: 35, person: CPerson(name: "Frank"))

//david.age = 23            // compiler error, as it should
david.person.name = "Sally" // this SHOULD be a compiler error,
                            // but classes do not support
                            // 'mutating' or const in general
david.person.name           // prints "Sally"

frank.age = 23
frank.person.name = "David"
frank.person.name // prints "David"
Problematic Swift Arrays

Swift – The Future for App Developers?

Myself, like most developers watching the WWDC keynote, I'm sure were shocked when Swift was announced. I think many of us have longed for a world where header files were a thing of the past, a syntax that could be freed from the C days of coding, and a generally safer language where it is harder to make little mistakes that could cause hours of debugging over a stupid mistake.

However, once developers started to play around with Swift, we realized a few sad truths:

  1. While the language is "ready for use", it is only so in the most basic of ways. Many features are missing, there are many rough edges, and there seems to be some fundamental design flaws in the language. And lots of editor and compiler crashes.
  2. The language promised performance, and while it may be faster than ObjC, many in the community are having a really hard time finding where that is true. Apple, please publish the code for your benchmarks so we can see the kind of Swift code we are supposed to be writing.
  3. The baggage of C may be mostly gone, but the language has clear design trade-offs to support better integration into ObjC. This doesn't seem like a win to be but rather the easiest way to bridge Swift and ObjC.

Before diving into the specifics, let me be explicitly clear: I think Swift is a step, a great number of steps in fact, in the right direction. And if some of flaws are fixed, the language will be a great improvement for the future of iOS and Mac development.

Header Files—Where are you?

Header files are gone! The only thing header files were good for, in my opinion, were create a nice contract for external consumers of your code. Other than that, they were a nightmare, especially in large projects. I've spent many hours tracking down symbols because other developers would simply not put all of their dependencies in the header files… I'm ecstatic that is no longer a problem!

The other great thing about no header is that we can take code that looked like this:

@interface Person {
  @property (copy, nonatomic) NSString *firstName;
  @property (copy, nonatomic) NSString *lastName;

  - (instancetype)initWithFirstName:(NSString *)firstName
                           lastName:(NSString *)lastName;
  - (NSString *)fullName;
@end

@implementation Person {
  - (instancetype)init() {
    return [self initWithFirstName:@"" lastName:@""];
  }
  - (instancetype)initWithFirstName:(NSString *)firstName
                           lastName:(NSString *)lastName {
    self.firstName = firstName == nil ? @"" : firstName;
    self.lastName = lastName == nil ? @"" : lastName;
  }

  - (NSString *)fullName {
    return [NSString stringWithFormat:@"%@ %@",
            firstName, lastName];
  }
@end

And define it as this:

class Person {
  var firstName : String
  var lastName : String
  var fullName : String { return "\(firstName) \(lastName)" }

  init(firstName : String = "", lastName : String = "") {
    self.firstName = firstName
    self.lastName = lastName
  }
}

This is such a big win. There are also some implicit differences about this contract:

  • Both the firstName and the lastName are enforced, at compile time, to never be allowed to be set to nil.
  • The member fullName is actually a computed property and not a method. This is only semantically different, but it provides an explicit statement of being a property of the class instead of a method that does work on the class.

Syntax—Nearly Perfect

I know I'm one of the few that actually enjoy the square-bracket syntax, well, as long as the nesting doesn't get too crazy. However, Swift takes us nearly all of way into the syntax of some of the more functional languages and some other scripting languages, like Python. This is just something you're going to have to get over (unless we can convince Apple to change its mind!).

Safe-by-default has also greatly added clarity to switch-statements as well. The ability to fallthrough while preventing accidental fallthroughs can only be seen as a win.

Closures are a nice addition, though semantically the same as blocks. However, we start to tread into some murky waters when looking at closures, the trailing closure syntax, and braces in general.

Swift, unfortunately, is still a curly-brace based language. This means that we write code like this:

var name = "David"
if name != "David" {
   println("Why is your name not David?")
}
else
{
  println("That's a great name!")
}

Now, I've purposely done something that will cause many holy wars across any code review: mismatched braces! Which line should the curly brace be on? Of course, the first is correct… or is it the second. I believe Swift should have simply fixed this issue as it's actually not even important.

var name = "David"
if name != "David"
  println("Why is your name not David?")
else
  println("That's a great name!")
endif

I think this is actually cleaner and creates less options for the developer. While options can be good, they should only be there if needed. Curly-braces have long not been needed in the world of programming.

Let's look at another place where this is actually an issue.

func measure(block: () -> ()) -> NSTimeInterval {
  let startTime = NSDate()
  block()
  let endTime = NSDate()
  return endTime.timeIntervalSinceDate(startTime)
}

Here we have a method that takes a closure and returns the amount of time it takes to run it.

measure({
  var x = 10 + 2
})

measure(
{
 var x = 10 + 2
})

measure() {
  var x = 10 + 2
}

measure()
{
  var x = 10 + 2
}

Unfortunately, only three of these are actually valid code; the last version is not valid and will result in two compiler errors. This is a parser limitation. Instead, had Swift gone away from curly braces all together, this problem could have been avoided.

func measure(block: () -> ()) -> NSTimeInterval =>
  let startTime = NSDate()
  block()
  let endTime = NSDate()
  return endTime.timeIntervalSinceDate(startTime)

measure() =>
  var x = 10 + 2

measure() => var x = 10 + 2

Now, this syntax allows for a common syntax for defining functions and closures and it works with trailing closures. There is a trade off though. If you look at the above, it really doesn't allow for defining those closures as a parameter though.

measure(=>
 var x = 10 + 2
)

That is terrible, do not do it.

let fn = () -> () => var x = 10 + 2
measure(fn)

That's the trade-off, and one I would have gladly taken. It's consistent and helps us write the code in a narrow set of ways.

Named Parameters—Um… What?

The named parameter implementation has got to be right up there as one of the roughest edges in Swift. I really do not like the fact that the API author is the one that dictates whether the name is required or not. I can see why this feature was added—interop with ObjC naming. But I do think it's the wrong design, especially for Swift-only code.

Let's take a look at the choices:

func add(x : Int, y : Int) { x + y }
class Calculator {
  class func add(x : Int, y : Int) { x + y }
  class func add2(#x : Int, _ y : Int) { x + y }
}

add(3, 6)                  // note: no names allowed
Calculator.add(3, y: 9)    // note, the x: is not present
Calculator.add2(x: 3, 9)   // note, the y: cannot be present

There are actually different defaults for the name requirements; functions are different than class members. The above is actually the only valid way to call those methods.

The following should be valid:

add(x: 3, y: 6)
Calculator.add(3, 9)
Calculator.add(x: 3, y: 9)

This is one of the places where the ObjC baggage comes across very strongly over into Swift. The Session 404: Advanced Swift WWDC talk gives an example of this and walks us through a story. In that story, we are told that this is just too verbose:

let wallWestOfHouse = Thing(location: westOfHouse,
  name: "wall",
  longDescription: "The plaster has crumbled away, leaving the wood beneath to rot.")

And that it would be really nice to be able simply write this:

let wallWestOfHouse = Thing(westOfHouse, "wall", "The plaster has crumbled away, leaving the wood beneath to rot.")

I agree, it should be. However, my argument is that both should actually be completely valid without putting that in the API and forcing one use or the other. In certain contexts the missing named annotations could be beneficial, but in others, it may not matter.

Not the end of the world, but I think this could have been cleaner.

Immutability—Or Lack Thereof…

At first, when I started to hear the mention of preference for immutable types, immutable by default, only use var when necessary, my hopes were high. There are such great things you can do in the compiler to optimize code that is dealing with immutable objects. However, as the details started to come out, it because clear that Swift doesn't actually have immutable types, only immutable values. This is very dissapointing.

This is the one part of Swift that I cannot seem to wrap my head around this decision and it's clearly not an oversight because there is documentation showing off the feature and how it works.

Let's take a look:

let tenEighty = VideoMode()
tenEighty.resolution = hd
tenEighty.interlaced = true
tenEighty.name = "1080i"
tenEighty.frameRate = 25.0

Source: Swift Programming Langauge: Classes and Structures

The let keyword is supposed define a constant such that "the value of a constant cannot be changed once it is set." What Swift has done though, is take that literally. For all object types, the "value" is the pointer to memory.

In the code sample above, everything is just fine because the memory address for tenEighty is never being re-assigned. I think this is a fundamental design flaw. Essentially, in Swift, it is impossible to create an immutable type. This has got to be addressed before going public.

Arrays come out as a very interesting case of this issue. The reason is that an array is actually a struct, but that struct has a pointer to the collection.

let items = [ "Bob", "Frank", "Sue" ]
items[0] = "Henry"
items

Paste that into a playground and you'll see the output is this:

[ "Bob", "Frank", "Sue" ]
"Henry"
[ "Henry", "Frank", "Sue" ]

However, the following code is not valid:

items += "Sally"

The idea that a developer has to understand how something is implemented to understand what is truly immutable about a type and what is not is broken. The fact that the "constant" array is not semantically immutable, is also broken.

In fact, nearly every useful optimization that we can make about parallelization and thread safety goes out the window because of this fundamental issue with Swift: there is not such thing as an immutable type.

Probably the most baffling reason for me is that Swift already has the correct foundation built to offer the exactly right thing!

struct Point {
  var x = 0.0, y = 0.0
  mutating func moveByX(deltaX: Double, y deltaY: Double) {
    x += deltaX
    y += deltaY
  }
}

var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveByX(2.0, y: 3.0)

let otherPoint = Point(x: 2.0, y: 5.0)
otherPoint.moveByX(10.0, y: 4.0)        // compiler error!

If Swift simply required every method on classes that updated member variables to need the mutating annotation, this problem would be largely solved. The only remaining piece would be the way in which to specificy a constant as a parameter to a method.

Summary

All in all, I'm really excited about Swift and the potential that it brings to the table. I've railed a bit on the weaknesses I've found in the language, mostly because I hope Apple will address them. Being able to play a role, however small it is, for a language that I will probably be using for a great deal of years to come on a platform I love to author on in is a very exciting prospect indeed.

Thanks Apple for a truly epic WWDC! And thanks to all of the Swift authors at Apple that will now have to hear from our criticisms and complaints about the language that you've worked very hard on and impressively kept under wraps for four years.

Swift – The Future for App Developers?

Benchmarking

If you are going to go out and claim that someone else is lying (see: http://www.splasmata.com/?p=2798), you really should back up your claims with provable and reviewable facts. In the case of benchmarks, you need to provide the following:

  1. The source code you used—this should be common sense. People should be able to peer review your work.
  2. Compiler and compiler flags used; without these, your results are meaningless.
  3. The average and standard deviation of your results.
  4. Test methodology used

This is the bare minimum. The author is missing all but #4.

For all of the following benchmarks, I used the Xcode 6 Beta build with the new XCTest performance feature. Tests were conducted on a Mid 2012 Retina MacBook Pro: 2.7GHz Intel Core i7 and 16 GB RAM. All tests were run under the standard Release mode settings.

So let’s look at the author’s claims:

Loop a million times

Swift: 0.0036s

Objective-C: .0021s (1.7x faster)

Since we have no code, we’ll have write our own.

Swift Timing (all three versions): 0.001s, 11 STDEV (gist)

ObjC Timing: 0.002s, 23% STDEV (gist)

Swift came out ahead here, but not by any statistically significant margin. Also, the author made the following claims:

  1. for _ in 0..999999 was “glacial”. The gist above shows this form to have identical performance to the other forms.
  2. ++ was really slow, yet the numbers say the same thing—identical performance to the other forms.

Seems like we’ve hit the basic problem: compiling with optimizations off—DEBUG builds.

Let’s check out the next one.

Increment

Swift: 0.024s

Objective-C: 0.0023s (10.4x faster)

The author claims that Swift has a performance problem with the ++ operator. Let’s check it out… oh wait, already did above. Yep, no issue in release builds. If we run the same tests under the debug configuration, we can see why the author is making the claims he made… oops!

We’ll take a look at one more:

Append native integer to native array

Swift: 6.51s

Objective-C: 0.023s (283x faster)

Ok, that looks like it hurts… let’s see if it is true.

Swift: 0.271s, 6% STDEV (gist)

ObjC: 0.039s, 38% STDEV (gist)

Looks like ObjC comes out on top here, but not by anywhere near the margins claim by the author.

Moral of the story, it’s best not to call people liars when your “facts” are poorly backed up. Also, benchmarks should always be peer-reviewable.

Swift has lots of potential issues with it, but performance over ObjC does not seem to be one of the big concerns.

Benchmarking