Sneaky Swift Tricks: The fake Boolean

Moshe Berman writes, “If I’ve got a bunch of chained guard let statements, how can I diagnose which condition failed, short of breaking apart my guard let into multiple statements? Given this example:

guard let keypath = dictionary["field"] as? String,
    let rule = dictionary["rule"] as? String,
    let comparator = FormFieldDisplayRuleComparator(rawValue: rule),
    let value = dictionary["value"]
    else
    {
        return nil
    }

How can I tell which of the 4 let statements was the one that failed and invoked the else block?

Or to summarize in Zork terms:

Given how less than perfect the Swift debugger is, it can often help to turn to everyone’s good old friend, the print statement. There is never a bug so profound that a surfeit of prints cannot detect it1.

My suggestion was to suborn the where clause and use it to provide feedback by calling a function that returns true but has a side effect of printing the file and line information:

func diagnose(file: String = #file, line: Int = #line) -> Bool {
    print("Testing \(file):\(line)")
    return true
}

The advantage of this approach is that it lets you know when the last guard fires, provides minimal intrusion onto existing code, and can be easily removed after debugging. Use it like this:

guard let value = optional where diagnose()

When a binding fails, the diagnosis will not print.

Screen Shot 2016-06-06 at 1.25.55 PM

While discussing this on slack, some interesting alternatives came up in conversation. Lily Ballard suggested extending Optional:

extension Optional {
    @inline(__always) func expect(@autoclosure msg: () -> String) -> T {
        guard let value = self else { fatalError(msg()) }
        return value
    }
}

He adds, “if you tweak it to return `T?` instead of aborting then you can just add `.expect("foo")` to any optional”

Davide De Franceschi had another take:

func diagnoseOptional<T>(optional: T?, message: String = "Found nil in \(#file) at line \(#line)") -> T? {
  guard let unwrapped = optional else {
    print(message)
    return nil
  }
  return unwrapped
}

He says, “Wouldn’t something like this be cleaner, although maybe a tad too specific?”

Joe Groff rocks it out by suggesting dump: the standard library dump function returns its parameter after printing an object’s contents using its mirror to standard output:

Another clever solution from Jérôme Alves:

If you’d like to see other feedback, Moshe also posted his question to Stack Overflow.

1 Took me forever to find where I had first written this, but I eventually spotlighted it (spotlit it?) up: “There is no problem so big so strong so bad that it cannot be solved with a surfeit of print statements”

3 Comments

  • I thought up another approach:
    https://gist.github.com/jayrhynas/d46026fbbebe88b2e701e1283412dc5f

    It only writes out the failures. It could also be extended to take an optional message to be printed with the existing message.

    The downsides are that because it uses tuples, you have to define a different `checkAll` method for each arity up to some limit, and there’s less of a visual relation between the clause and it’s bound variable in the guard statement, especially when the statements being unwrapped are long.

  • Custom operator alternative: reports both success & failure
    https://gist.github.com/AfricanSwift/6ed839400c4fec442db411371f0487da

  • This is a tooling problem. I know that it will be extremely difficult to go back from fully optimized code to the source line but that is exactly what is needed. The alternative is the source code gymnastics we see above.