Guarding with diagnostics

So I was reading a question someone passed by me today, and completely ignoring their question for the moment, my eye was caught by the following pattern:

let firstName: String = ""
let lastName: String = "Smith"

// Choice 1: Original Recipe
func basicGuard() -> Any? {
    guard !firstName.isEmpty 
        else { print("firstName can't be empty"); return nil }
    guard !lastName.isEmpty 
        else { print("lastName can't be empty"); return nil }
    return "something"
}

And I was thinking, surely there’s a nicer way to do this. So just brainstorming, I came up with the following two:

/*
   Debug flag is set in Build Settings > Custom Flags > Other Swift Flags
   See: http://i.imgur.com/GA7M4T4.jpg
*/

// Choice 2: Using Infix Operator

func debugOnlyPrint(_ items: Any..., separator: String = " ", terminator: String = "\n") {
    #if debug
        print(items.map({ "\($0)" }).joined(separator: separator), terminator: terminator)
    #endif
}

infix operator **
func **(condition: Bool, message: String) -> Bool {
    if !condition { debugOnlyPrint(message) }
    return condition
}

func infixoperator() -> Any? {
    guard
        !firstName.isEmpty ** "firstName cannot be empty",
        !lastName.isEmpty ** "lastName cannot be empty"
    else { return nil }
    return "something"
}

// Choice 3: Using an enforce function

func enforce(_ rule: String, _ condition: @autoclosure () -> Bool) -> Bool {
    let passing = condition()
    if !passing { debugOnlyPrint(rule) }
    return passing
}

func enforcement() -> Any? {
    guard
        enforce("firstName cannot be empty", !firstName.isEmpty),
        enforce("lastName cannot be empty", !lastName.isEmpty)
    else { return nil }
    return "something"
}

So let me ask you, of these three, which do you like the best? And why?

Moving on to the question that was actually asked: what’s an easy way to print a return value for debugging? You can use any of a number of diagnostic solutions, I kind of like this one:

func here(_ note: String = "", line: Int = #line) -> Bool {
    if note.isEmpty { debugOnlyPrint("[line \(line)] ", terminator: "") }
    else { debugOnlyPrint("[line \(line) \(note)] ", terminator: "") }
    return true
}

precedencegroup VeryLowPrecedence {
    associativity: right
    lowerThan: AssignmentPrecedence
}

infix operator ?* : VeryLowPrecedence

func ?*(_: Any, item: T) -> T {
    debugOnlyPrint(item); return item
}

To use this, place a call to here() followed by ?* in-line before your return item, for example, return here() ?* "something". It prints out the line number followed by the return value. Operating at a very low precedence enables the entire return expression to be evaluated before printing.

4 Comments

  • Hi Erica! I believe this is your response to my Tweet linking to my original question on StackOverflow :).

    I really like the “enforce” function. But as I suggested in my post on SO, it would be so cool if the “defer” statement would expose return value! 🙂

    • Did you continue down to the bottom with `here() *?` ?

      • Yes very elegant indeed! 🙂

        But we still have to problem with multiple exit points from “advanced” methods such as the “fetchUserByFirstName” in my original post.

        The cool thing with “defer” is that we know that the code in that scope always will be called disregarding of exit point.

        So it is really too bad that the return value is not exposed!

        But I will make use of your “here() *?” 🙂

        • You can throw in result = whatever, return result, and then use defer to print but I find that kind of excessive

          var result: T? = nil; defer { print("exiting \(#function): \(result)") }
          
          guard whatever else { return result }
          ...
          result = something
          return result
          

          You can also do a pass-through operator, which would allow `return result := something` or `return setValue(inout result, something)`. Again ugly.