Dear Erica: Help me refactor

Mike writes: How can I refactor this so I don’t use the same fail logic twice and won’t incur the costs of the expensive call unless needed? Is there an elegant one-line condition I can use to replace the nesting and redundancy? Using guard for early exit on myCondition is a no-go.

Here’s the code:

// Not ideal: Dupe fail logic
if !myCondition {
    if let myValue = getExpensiveComputationResult(){ 
        // Do my stuff 
    } else { 
        // Fail logic 
    }
} else {
    // Fail logic AGAIN
}

// Also not ideal: computation always processed regardless of myCondition
if let myValue = getExpensiveComputationResult() where !myCondition { 
    // Do my stuff 
} else { 
    // Fail logic 
}

A lot of developers new to Swift miss compound if statements. These consist of comma-delineated expressions which are evaluated in order. Compound if statements can include constant binding as in the following refactored code.

func expensiveCall() -> String? {
    print("EXPENSIVE!"); return "Expensive"
}

if !myAutoFailCondition, 
   let foo = expensiveCall() {
    print("Success, but expensive")
} else {
    print("Fail condition")
}

This example short-cuts if the “myAutoFailCondition” is true and the expensive function is never called. I encourage you to try this out in a playground.

The Swift if statement’s components can include a single expression that evaluates to true or false, an optional-binding condition, an availability condition, or a case condition. Always put the simple expression first or you’ll need to use where to separate it from the other kinds of checks. You’ll find the full grammar at the back of the Swift Programming Language book.

2 Comments

  • func expensiveCall() -> String? {
    print(“EXPENSIVE!”); return “Expensive”
    }

    IMHO, this is not well written code (although Swift compiler incorrectly allows it?)

    the function ALWAYS returns a value, so the return type “String?”, should be “String” and only “String”.

    i understood that “String?” was to allow the function to return nil

    am i missing something about Swift?

    • You can’t use conditional binding with String. It has to be String? for the example to work.