Matthew Burke

Mathematician, Software Developer

Just Because You Can...

The other day, I read the post Boolean on Apple’s Swift Blog. The post sparked a flash of inspiration, so I opened up Xcode and entered the following code

1
2
3
4
5
import Foundationn

if "this is a test" {
    println("This can't work.")
}

Perhaps you are expecting a compiler error. Nope. The output is, of course,

This can't work.

Then I tried the following

1
2
3
if "this is not a test" {
    println("No, really, this can't work.")
}

Xcode displayed the output

No, really, this can't work.

One last code snippet

1
2
3
4
5
if "you know what's going on" {
    println("You're a genius!")
} else {
    println("So sad!")
}

I’ll let you determine for yourself the appropriate output.

The point of the exercise

To be honest, there’s not much of an actual point here. I just found the Swift code amusing.

Sure, I could argue against using overly-clever code in production. And I would never use a trick like this in production code. But I don’t need to argue against this practice, because nobody’s arguing for it.

Now, before you repsond because DSL, let me point out, I’m all for domain specific languages (DSLs). I’ve given talks on DSLs in Forth and TCL (such as this one). I’m jealous that Mattt (not a typo) Thompson beat me to the punch with Euler. So, I’m all in favor of DSLs, not to mention operator overloading, code generators, and metaprogramming. They’re all good!

But the primary purpose of code is to clearly communicate with other programmers. (What? You thought it was to tell the computer what to do? That’s soooo quaint!) One of my favorite CS-related quotations is from Brian Kernighan

Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, 
you are, by definition, not smart enough to debug it.

Metaprogramming, operator overloading, etc. often times make our code harder to read (hence, harder to understand/debug) because they increase the amount of context we have to maintain. There are many situations where using macros (real macros, Lisp-like macros, not puny C preprocessor macros), or operator overloading, or creating a DSL is warranted because it clarifies our communication, but every time we are tempted to use such a technique, we have to ask ourselves are we using this technique because we need to, or are we using it because we can?

The code behind the curtain

First, I should fess up. In case you didn’t notice it, at the beginning of the code listing, it’s not Foundation that I’m importing, it’s Foundationn. The former is Apple’s module containing definitions for all the, uhm, well, foundational classes. The later is a module I cooked up to be deceptive^Wclever. I’ll list the code below.

The main decision to make is how to map strings to boolean values. Once you’ve decided on a mapping approach it’s a simple matter of using an extension so that String implments the BooleanType protocol. I did it as follows:

1
2
3
4
5
6
7
8
9
10
11
extension String : BooleanType {
  public var boolValue : Bool {
    get {
      if self.contains("test") {
          return true
      } else {
          return false
      }
    }
  }
}

String (at least as of Beta 5 and, yes, I’ve been a little slow posting this) doesn’t implement contains. I use the following which I grabbed from StackOverflow.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
extension String {
  func contains(other: String) -> Bool {
      var start = startIndex

      do {
        var subString = self[Range(start: start++, end: endIndex)]
        if subString.hasPrefix(other) {
            return true
        }

    } while start != endIndex

    return false
  }
}

I wound up with the above code to check string containment after trying a half-dozen different approaches that various people claimed worked. I suspect they all did for one beta or another. Presumably with the 1.0 release of Swift (and 1.1 around the corner), the pace of change in Swift will slow down (but not stop, since much as I like Swift, it still has a lot of growing up to do).

If you’d like to play around with branching on strings, you can download the workspace I created from https://github.com/profburke/ObscureSwift. I’d like to collect more Swift oddities, so feel free to add an issue or send push requests if you have anything to contribute. Given the previous paragraph, YMMV.

Spanning Xcode betas

One final note. I was working on this during some less-than-ample-spare time and new Xcode/Swift betas kept popping up before I was finished.

This was not fun.

In case this remains an issue with new releases, here’s the little dance I had to perform for each new version in order to get Swift to recognize the Foundationn module:

  • delete the derived directory for the project
  • remove the pcm file from the module cache (under the DerivedData directory)
  • delete the playground file
  • build the module
  • recreate the playground file

Once the Xcode release for Yosemite comes out, I’ll test this again, and submit a radar as necessary.