Static Wins! RAH RAH!

Warning: This is a bit of a rant; you’ve been warned.

Recently, the Swift team published this blog: What Happened to NSMethodSignature?

This is the first thought that went through my head:

Or which one of you, if his son asks him for bread, will give him a stone?

Matthew 7:9

Seriously, someone asks for the functionality for dynamic dispatch and you say you can do the same thing with static code! No, you cannot. You can mimic the behavior.

Instead, you showed someone how to build a static registration table. Then you make the statement that it’s “type-safe” while using Any as the arguments to the public API for dispatch and using type coercion… that’s not type-safety. And let’s be honest, it’s really not that different then the validation one does for dynamic dispatch either.

To make matters worse… no one writes that type of code for long without using MACROs because you end up with soooooo much duplicated, boiler plate code. But of course, Swift doesn’t support MACROs. Now you have two choices:

  1. Copy-paste for all the registration items.
  2. Build a custom tool to create the code from some metadata.

You see, and this is the trade-off that you never mention. You paint an extremely biased position without covering the full gambit of what is really needed to build and maintain a system like you are proposing. The reality, it sucks.

And that’s what really irked me about the post: you state the static registration table as the right and better way to solve the problem but speak to none of the drawbacks.

I’ve built systems using both static dispatch tables and dynamic invocation. I cannot say that I’m looking forward to building those same systems in Swift today.

Static Wins! RAH RAH!

Silently Failing

Over at Human Friendly there is a blog post about needing an AssertingNilCoalescing operator: !!. I get what is being said: you have an Optional that shouldn’t be nil (it’s an Optional for many reasons, typically outside of your control such as a bridged item from ObjC). Sounds reasonable, after all, no one likes crashing apps and the alternative is to use the if-let form to handle the case (or the shorthand ??).

So instead of writing this:

assert(opt != nil)
let foo = opt ?? safeValue

You use the shorthand version:

let foo = opt !! safeValue

Sure, it’s more terse. However, and this is the main reason I do not like this pattern: it is introducing a class of bugs that Swift has intentionally chose to make hard to get into and the very reason some are choosing to rewrite everything in Swift.

We did indeed see surprising patterns in the causes of these bugs. I found myself repeatedly saying to myself or Janie that a particular bug wouldn’t have even compiled under Swift, or would have thrown an immediate exception. When we totaled up bugs like this, we found that 40% of bugs shipped to customers in the last three years would have been caught immediately by using Swift. The primary classes of these bugs were:

  • Silent failures due to nil-messaging (emphasis added)
  • Improperly handled NSErrors, or other Objective-C error failures
  • Bad object typecasts
  • Wrong enum lookup tables being used for values

Source: http://www.sunsetlakesoftware.com/2014/12/02/why-were-rewriting-our-robotics-software-swift

This operator is introducing the same exact semantics that some are trying to run away from.

If opt is never supposed to be nil, then do an assert on it and log those errors using some sort of telemetry system or simply force unwrap it. The crash logs will help you find these issues and fix them, silently failing will not get you that information.

And you won’t find these issues in testing when using assert unless you also test against debug builds. If you are testing debug builds instead of release builds, then you really are not testing the product you’ll be giving your customers… but that’s a topic for another day.

Silently Failing