Custom Control Structures in Swift

Posted on

Apple’s new language Swift has some really nice syntactic sugar for common operations. One of the new features is closures which are similar to blocks in Objective-C, but they have a few tricks that blocks don’t have. When the last argument to a function is a closure it’s possible to put it outside the parenthesis of the call to the function. This makes it possible to write control structures which look(almost) identical to the normal control structures.

Reimplementing the if-statement

Let’s use these trailing closures to reimplement the if-statement

1 func _if(condition: BooleanType, action: () -> ()) {
2   if condition {
3     action()
4   }
5 }
6 
7 _if(1 < 2) {
8   println("1 is less than 2")
9 }

The second argument to the function _if is a closure with no parameters and no return value. It has the type () -> (). Because the last argument is a closure it can be moved outside of parenthesis that make up the method call. Unfortunately we still need to parenthesis to invoke the function which is not the case for the real if statement, but we can just pretend this is C.

The BooleanType is a protocol that can be adopted to allow any type to work with the various control structures in the language such as if and while

If without if

There is a problem with the _if function though - it uses the if statement which makes it extremely redundant and unimaginative. Could we implement it without using the if keyword? Yes we can.

 1 func _if_without_if(condition: BooleanType, action: () -> ()) {
 2     // We fake the false case by using an empty closure, e.g a NOP
 3     let actions = [{}, action]
 4 
 5     // boolValue returns a Bool and we can abuse the fact that
 6     // hashValue of true is 1 and then hashValue of false is 0 to
 7     // get the correct closure to run
 8     actions[condition.boolValue.hashValue]()
 9 }
10 
11 _if_without_if(1 < 2) {
12     println("1 is less than 2 even without if")
13 }

This is the solution I came up with, but I’d love to see more ways of doing it.

Reimplementing the while-statement

How about while? Can we implement it in the same way?

 1 func _while(condition: @autoclosure () -> BooleanType, action: () -> ()) {
 2   while condition() {
 3     action()
 4   }
 5 }
 6 
 7 var i = 0
 8 _while(i < 10) {
 9   println("\(i)")
10   i += 1
11 }

Here I am using a Swift feature called auto closure which wraps any expression passed in a closure. This is why the condition is prefixed with @autoclosure. Without this there would be no way to reevaluate if the condition had changed as a cause of the loop body, we would have an infinite loop or no loop at all. Again we can use the trailing closure syntax to closely emulate the native while.

While without while

Again the _while function is cheating and uses the while statement to accomplish it’s function. Here’s my solution without using while.

 1 func _while_without_while(condition: @autoclosure () -> BooleanType, 
 2                           action: () -> ()) {
 3   var loop: () -> () = { $0 }
 4   loop = {
 5     // The condition is called each time to 
 6     // see if the loop should continue
 7     if condition() {
 8       // Then the acutal action is called
 9       action()
10 
11       // Lastly the closure calls itself recursively
12       loop()
13     }
14   }
15 
16   // This sets off the first loop iteration
17   loop()
18 }
19 
20 var j = 0
21 
22 _while_without_while(j < 10) {
23   println("\(j)")
24   j += 1
25 }

Useful examples

The examples shown above are nothing but hacks for the sake of fun. Let’s now look at some examples of control structure which are more useful. Starting with a something that ruby and perl programmers will recognize, unless.

Unless

unless is a keyword found in ruby and perl. It’s essentially a reverse if statement which will branch if the condition is false.

Here it is in swift

 1 func unless(condition: BooleanType, action: () -> ()) {
 2   if condition.boolValue == false {
 3     action()
 4   }
 5 }
 6 
 7 var opt: Int? = 10
 8 unless(opt == nil) {
 9   println("opt was non nil")
10 }

Ruby programmers might miss the infix version of this keyword which looks like this action unless condition. Well thanks to Swifts operators we can implement that too, albeit without the nice name.

 1 // Define the ++= operator
 2 infix operator ++= {}
 3 func ++= (action: @autoclosure () -> (), condition: BooleanType){
 4   unless(condition, action)
 5 }
 6 
 7 var x = 1
 8 
 9 // This is equal to ruby's
10 // x = 2 unless 1 > 2
11 (x = 2) ++= 1 > 2
12 
13 println("\(x)")

Don’t do do that in real code though. Operator overloading and definition should be used sparsely.

Maybe

Imagine you are writing a game and want something to happen sometimes. For that there’s the maybe operator which executes the specified action 50% of the time.

 1 // Perform some action 50% of the time
 2 func maybe(action: () -> ()) {
 3   if arc4random_uniform(2) == 0 {
 4     action()
 5   }
 6 }
 7 
 8 maybe {
 9   println("Hello World?")
10 }

Threads

As most iOS developer learn the hard way modifying the UI from any thread but the main thread is not a good idea. This task is so common that it deserves a control structure. As does the task of performing a task in the background.

 1 func onMainThread(action: () -> ()) {
 2   dispatch_async(dispatch_get_main_queue(), action)
 3 }
 4 
 5 onMainThread {
 6   myView.hidden = true
 7 }
 8 
 9 func inBackground(action: () -> ()) {
10   dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), action)
11 }
12 
13 inBackground {
14   fetchDataFromInternet()
15 }

Discussion

After posting this post some interesting discussion was brought up. Reddit user drewag pointed out that the return statement doesn’t play very nicely with these custom control structures because it will simply return from the closure rather than returning from the enclosing function. This is in part mitigated by the fact that the return has to be a void return to not cause a compiler error. Still it’s good to keep in mind.

@Fudmottin pointed out the similarity to Common Lisp Macros. He also went ahead and tried his hand at implementing a do...until control structure which I used as a base to build my own implementation.

 1 // The DoUntil struct holds the action that is
 2 // the loop body
 3 struct DoUntil {
 4   let action: () -> ()
 5 
 6   init(action: () -> ()) {
 7     self.action = action
 8   }
 9   
10   // Using a method like this allows replacing what would have
11   // been a space in 
12   // do {
13   //    println("i = \(i)")
14   //    i++
15   // } until (i == 10)
16   // with a dot instead
17   func until(condition: @autoclosure () -> BooleanType) {
18     while condition().boolValue == false {
19       action()
20     }
21   }
22 }
23 
24 func Do(block: () -> ()) -> DoUntil {
25   return DoUntil(action: block)
26 }
27 
28 i = 0
29 
30 Do {
31   println("i = \(i)")
32   i++
33 }.until(i == 10)
34 
35 i

A few people also weighed in on whether this is a good idea in practice. For now I consider it a good demonstration of Swift’s capabilities which, when used correctly make for powerful semantic tools.

Join the discussion on Reddit