1 2 3 4 5
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
Xcode displayed the output
No, really, this can't work.
One last code snippet
1 2 3 4 5
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
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
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.