Swift 2.0: Why Guard is Better than If

Swift 2.0 comes with the excitement of the guard statement. But looks like there’s still confusion as to why guard is AMAZING, especially compared to the simple if statement before Swift 2.0.

That is a completely reasonable question. So why is guard better than just a plane if? Let me count the ways…

The Setup

I’ll use the same example as in my Error Handling blog post – a simple form with a name and age field – so please take a look at it before proceeding.

The part I’ll be focusing on is the viewModel, specifically the createPerson() function:

Here are the benefits of using the new guard paradigm in the createPerson() function:

Pyramid of Doom

I’ll start with the most obvious – the infamous Swift Pyramid of Doom. Here is what the createPerson() function would look like using the if statement:

Sure, the Pyramid of Doom get a little better with the Swift 1.2 unwrapping of multiple optionals on the same line, but you got to admit this is not pretty and hard to decipher the meat of this function (actually creating the Person!) at first glance.

Compare this to the above implementation with guard – it’s so much more readable with the Person being returned at the very end, making it clear that that’s the main goal of this function all along.

Return Options

Notice that when using the if statement version of the createPerson() function (without the guard), we have very limited options on the return value.

In my case, I’m returning an optional Person – the person either exists or not. This puts an additional Pyramid of Doom responsibility on the caller of this function:

But what if you want to be more specific – if there’s an error, you want to return what the exact error is to show to the user filling out the form. Well, in this case, you would do something like this:

This Haskell-like Result Enum solution is not bad, except for the fact that you’re now returning a PersonResult instead of a Person like you meant to and you can ignore the failure option if you wanted to.

With the new guard syntax, the return value is what it’s meant to be – in this case you’re meaning to return a Person object, and the compiler forces you to handle the error cases when the Person is not returned as expected:

Screen Shot 2015-07-16 at 5.47.01 AM

So the caller’s result catching syntax with guard looks like this:

Happy-Path Programming

Finally, the most elegant thing about using guard vs other programming paradigms (like the nested if statements) is that you’re coding for the happy path while still being forced to handle early exits caused by possible errors. It reminds me a lot of the famous Railway Oriented Programming talk.

Recipe_Railway_Transparent

You’re coding for the green, with early exits if things go red at any point. It’s a very elegant way of approaching code without the overwhelmingly complicated functional syntax described in the talk. Reading the code, you can immediately see what the happy path is:

I’m sure I’m missing some other points on what makes guard so awesome, so feel free to contribute in the comments!

Enjoy the article? Join over 17,500+ Swift developers and enthusiasts who get my weekly updates.

  • Jason R Tibbetts

    One of the great things about throwing specific error types is that it makes u it testing much more robust. No longer are you limited to checking, say, nil returned by an initializer is *any* argument is wrong; now you can catch specific error types.

    • Good point! Just wrote a test yesterday in Swift 1.2 where I had to test nil vs something.

  • Kakubei

    Thanks for this. One little thing though, I think you want “plain” instead of “plane” in “better than just a plane if? “

  • Hi Natasha, your blog is now in my favorite. Reading this article, I’m still wondering about the “specialness” of guard syntax. I feel it would be quite the same to negate every if statement and return the “exception” in each of them. At least It’s what we are used to do in our application.

  • Vjosullivan

    Interesting article but it misses the elephant in the room. It is the always responsibility of the code that calls createPerson() to ensure that the required data is set up prior to making the call. The contract of any function is always only “If you give me valid input then I will return valid output.”. No more, no less. createPerson should be a one-line return statement.

    The presence of a data validation guard statement at the start of a function is a very strong indication that there is something wrong in the calling code. It is calling a function without checking first that it makes sense to do so.

    Followed to its logical conclusion, ensuring that preconditions are met before calling functions results in most error handling actually vanishing from the system.

    • Tosin

      So I think you’ve got to have the validatoion code somewhere and it’s prob better to have that in the ViewModel. The only other places it could be put would be in the ViewController or a seperate helper class, but eventually that validation code has to be written and logically keeping the validation & creation together in the view model sounds like the best of those three situations.

      Correct me if i’m wrong.

      • Vjosullivan

        Yes, validation code does have to go somewhere. It should be encapsulated in one place, if possible. That place should not be in the createPerson() function but in its own function.

        If you wait until after you have called the createPerson() method to check if you have enough data to perform the method then you are, in effect, using exceptions to control the flow through your program. This is generally regarded as bad practice. ( http://stackoverflow.com/questions/729379/why-not-use-exceptions-as-regular-flow-of-control )

        Swift functions should follow the Single Responsibility Principle ( https://en.wikipedia.org/wiki/Single_responsibility_principle ). Data validation (including user input validation) and object creation are two different responsibilities and should be handled separately, in different functions. The net result will be that each function will be shorter, more focussed and easier to test.

        These principles generally fall under the heading of “Design By Contract” ( https://en.wikipedia.org/wiki/Design_by_contract ) and its evil twin “Defensive Programming” ( https://en.wikipedia.org/wiki/Defensive_programming ).

        Using Swift’s guard statement to validate parameters and throw errors can probably be described as a good way to implement a bad practice.

        • Is this example, with the Person struct initializer checking data validity when creating an instance of the Person value type really appropriate for the single responsibility principle?

          Shouldn’t the data validity remain in the value or reference type rather than create a dependency with the view controller or worse a separate data input validity checker? After all, if the Person struct changes, now instead of just worrying about making sure all the code within Person handles those changes you also need to make sure your view controller or data validating code elsewhere do as well. Now, to me, that doesn’t make things more robust but instead more fragile. What am I missing here?

          The Single Responsibility example linked on Wikipedia makes sense I pointing out that format, which I’m assuming is a UI issue, and content are very different associations for the form module. But Person value type initialization, and making sure that the values coming from the view controller are appropriate for the initializer, seem very closely linked.

          • Vjosullivan

            When out shopping, which is the better strategy? 1) Start at the checkout counter (aka createPerson()) and wait for the attendant to see if you have any goods in your basket and enough money in your purse, tell you where you’ve gone wrong and send you away? or 2) Check that there’s enough money in your purse, check that the basket contains the goods you want and then go to the checkout counter?

            Both strategies work. Which would you prefer the ten people in the queue in front of you to be using?

          • John Kountz

            By your strategy, the caller would verify that the credit card has sufficient funds before attempting the purchase. That simply is not done in any real system.

            I take exception with everything you’ve suggested as best practice, but i respect your opinion.

          • Vince O’Sullivan

            (I know I (almost) always ensure I have enough funds before making a purchase but I don’t think that that’s what you’re really referring to.)

            I may be wrong but I think that it’s highly unlikely that real systems start a transaction to debit a credit card and then catch any mistakes afterwards. The card machine won’t even call the bank, if the card number has an invalid format or has expired. The bank will ignore anything that doesn’t come from a valid source. Even if the card format is correct, it needs to find a matching account. It won’t attempt to debit an account that has been locked or closed, etc. Hopefully, all checks out then it can start to look at the account itself and check the credit worthiness of the account against the requested amount. Only if all the details have been verified would a relatively expensive debit transaction even be attempted.

            Verification and error handling are important all the way through any system, but each component of the system should only be attempting to handle errors that occurred locally not errors that happened elsewhere in the system which have resulted in bad parameters being passed down the line. Those errors should be handled at their source.

            The “Railway Oriented Programming” technique – that Natasha referred to – does exactly this. The railway diagram above clearly shows separate and independent validate and update functions. The problem that I’m calling out is in the createPerson() code example; where the guard statement is being used to generate errors that should already have been covered in a separate validatePerson() method that gets called first. Which brings us back to my original point: You shouldn’t be using a guard statement to validate parameters because you should never send a method invalid data.

          • John Kountz

            Appreciate your thoughtful response Vince. Communication is the hardest thing we do, many problems are rooted in the communication.

            Which brings me to my follow-up, i was referring to the Merchant side of the system. The Merchant does not make a call to verify the balance first, hells no. That code might not even validate the credit card source data. It prepares whatever input it might have, and shuttles a call off to the merchant bank service to place the purchase transaction.

            For the merchant bank to NOT validate the basic input would be simply silly, no? Not doing so would open the merchant bank web service to DOS attacks.

            Best security practice’s recommend defense in-depth, and following that standard, the merchant bank API end-point should do all appropriate validation without making assumptions that the caller was providing valid, and range appropriate data.

            Perhaps we agree more than I thought.

            How would you address the defense in depth mandate for providing secure services?

          • Vince O’Sullivan

            At a system level, I’m sure we’re in agreement. The bank metafor is at danger of clouding the argument because we’re talking about a whole system with multiple responsibilities. Defence in depth is a higher level concept and – by definition – requires multiple components to work together as a system.

            Design-by-contract works at the individual method level, alongside the single-responsibility principle. A single method should validate data or action it but it shouldn’t do both. The validation contract is “Give me data and I’ll tell you if it’s valid.”. The action contract is “Give me valid data and I’ll do the right thing with it.”. At no point should a “bad parameter” error be being thrown. Obviously, other errors may occur but not “bad parameter” because the data should be validated before it is sent not after it is received.

            Defence-in-depth assumes all data is potentially invalid; therefore it must always be validated before it is actioned. The principles turn out to be remarkably similar.

          • Jay

            Vince, does this imply that validation function alone should ever take optionals as parameters? (vs action functions)

          • Jay

            Vince, I like the approach in the playground you posted on github. However, when the developer forgets to call personCreateable() the app will crash when the name or age are not set properly.

            Natasha, just as your blog, the guard method is awesome. I would encapsulate all error handling within the struct to make it more self-contained and avoid duplicating code.

            I forked Vince’s code and would be curious to hear what you think about it (https://github.com/yogoo/ContractExample/tree/hybridMethod).

          • Vince O’Sullivan

            “when the developer forgets to call personCreateable() the app will crash when the name or age are not set properly.”

            Yes, this is what you would hope for and expect. Not validating data before acting on it is a bug that should come out in testing.

          • Mark Bura

            So if you or anyone is going to test your code then something like this would happen? (Hey you need to call this method first if you want to create a person O_o … !!!!) … createPerson() test will FAIL (by Crashing!!) and its going to be your fault .. furthermore looking at your sample : Person(name: name!, age: Int(age!)!), sorry but all those forced unwrapping makes me a headache, I can’t see how your point of view could be better that using Natasha’s approach, for a reason Apple introduced those features in swift 2.0 (guard, try, catch) .. BTW awesome blog Natasha!

          • Vince O’Sullivan

            Why would you attempt to create a person, if you don’t have the right data to do so? If you don’t know if you have the right data the logical action is to find out first, not to blindly pass invalid data through the system and hope it gets spotted further down the line.

            It’s not “your fault” if you crash because some other part of the system is sending you invalid data. It is the fault of the component sending that data. The cure is not for every method to predict and handle all the possible forms of bad data that might be received from all possible senders (and throw an error that the sender may or may not handle). That is merely treating the symptom. The cure is to fix the sender and eliminate the bad data from the system before is gets sent. Errors should only be thrown for errors that occur locally. Receiving bad data is the result of an error that has occurred elsewhere.

          • Thom Jordan

            Reading through this thread has been very helpful for me to start considering the details of each approach and when to use them. After some thinking, my strong opinion is that to create robust components and systems, both approaches need to be taken seriously and in parallel. “Guards” are named as such to suggest that they enforce a construct’s precondition contract, by guarding its input without knowing where it’s coming from, or who’s sending it. To perform these tests outside of a function demands that the function must assume something about the context in which it is called. In regular OOP, this is much easier for a programmer to enforce, simply by calling the related testing function immediately before the function which is trusting it to do so. The contract then becomes arbitrarily enforced by an implicit agreement by a programmer to write code that performs individual tasks in an implicitly-prescribed order. As modern languages such as Swift move further from inheritance-based OOP and more toward “Ad-hoc Polymorphism”, which the motivation for the addition of “Protocol Extensions” in Swift 2.0, these types of programmer-enforced coding conventions begin to take on the form of anti-patterns, in that receivers must somehow guarantee that they know that they will never be called with an incomplete or faulty input. In practice, this makes a superior design decision like delegating control from the output point of a queue pretty much impossible when there’s more than one kind of value or object appearing at its receiving end. Independently, the design of any robust system must immediately start making decisions based on exactly what Vince is describing, the Design-by-Contract approach. Just as it’s undesirable for the design to automatically assume that checks will be happening on the receiving end, it’s just as undesirable for receivers to assume that their preconditions will always be fulfilled upon their invocation. To create a fully modular design, the use of guards according to Natasha’s original post is crucial to ensure against unanticipated crashes, while approaches to program design that enforce Vince’s argument as much as possible should lead to a program architecture that is safe and efficient by nature, where guards wouldn’t need to be applied everywhere to compensate for a underspecified design. Both approaches are needed, and striking the right balance for each set of requirements largely remains a design challenge. The use of guards now should help greatly in communicating intent, which should inspire better designs to emerge more quickly.

          • Thom Jordan

            Here’s a stellar presentation by Rich Hickey, the inventor of Clojure, which explains much of the motivation behind designing for modularity at the functional level, a much more flexible and finer granularity than OOP can achieve: http://www.infoq.com/presentations/Simple-Made-Easy

          • apluralist

            Rich Hickey’s OOP straw man tour is still making the rounds people. He shows how if you do objects wrong, they don’t work! But parentheses everywhere do! lmao

          • Thom Jordan

            LOL.. I hadn’t seen it until recently.. It was nice to hear Rick’s perspective and his clear articulation of concepts which I’ve been vaguely considering for awhile it seems.

          • apluralist

            What I see on this thread is attempts to deal with a fundamental misunderstanding. DbC’s biggest proponent, Bertrand Meyer, explains all this quite clearly. The person here arguing for contracts clearly never read that explanation. Yes, the API must publish pre and post conditions, but, there has to be a means of enforcement. M would never sign on to this idea that ‘I told you what to do and you didn’t do it.’ Frankly, the crazy thing about DbC is that what it needed all along was simply a compiler and a runtime-enforcement mechanism. Meyer’s main argument against inline validation is that it dirties up the code and obscures the logic. But if you read his thing about Ariane 5, he would for sure say that the precondition that the trajectory points be scoped to a range would be enforced in the code, not simply stated in the docs. The whole idea M was after was provable apps, e.g. apps that we KNOW work, not that will work if each proclamation was followed to the t.

          • Thom Jordan

            After two months of using the guard construct, I must say that it absolutely rocks. It has turned writing error-checks into something much more enjoyable.

          • apluralist

            I totally agree. Some of it feels a little upside down. But for sure one of the best things about the Swift team is that they are trying really hard to do things that will result in code that is absolutely clear as can be. Who would have thought that maybe pre/post condition checking should merit another keyword! Plus, it is a good idea to avoid the pyramid of doom. Youngsters think that’s not even real and don’t see the point, but commercial C code is completely unreadable for all the nested ifs and checking of return values.

          • Vince O’Sullivan

            Not necessarily. If certain data is mandatory, why send a nil value to be validated? If other data is optional, then it is OK for the action function to accept optionals (but it should still be valid if present).

        • Would love to see your version of the code so I can learn from it. Please post on github and I’ll take a look. It’s hard for me to imagine what you have in mind just from Wikipedia articles.

          • Vjosullivan

            OK take a look at an (Xcode 7β4, Swift 2.0) playground example at https://github.com/vjosullivan/ContractExample

            It’s not perfect code by any means but illustrates the points I was trying to make. The guard syntax is nice but parameters should be confirmed before an operation is invoked. Doing it afterwards, is an anti-pattern. Any error thrown by createPerson() should only arise from a failure that has occurred despite the presence of valid data.

          • So where do you throw the specific errors to notify the user of what information is missing / incorrect?

          • Vjosullivan

            There is no missing or incorrect information before calling an operation only after making the call. The real error is in making the call without the required data. It is an error in the code not in the data. The difference is subtle but important.
            Documentation should specify the preconditions necessary for a function to work. (If you’re calling undocumented functions all bets are off (and guess what, my example was initially undocumented).) The author then codes the client accordingly. Unit tests of the client during development will ensure that the client never calls for an operation without meeting the operation’s documented preconditions.

            Given the above, the whole concept of missing/incorrect data gets written out of the system.

            Even where the client code is taking input directly from a user, the client has the job of validating that user’s input before calling the operation. Given a documented operation, the client does not even need to consult the model to guide the user into providing valid data. So there’s still no concept of missing/incorrect data that the model needs to handle.

  • Small bite sized, we we like it

  • Pingback: Swift 2.0 In A Nutshell | Ahmed Abdurrahman()

  • Ian

    Why would anybody fall into the “if pyramid of doom”? You just can use if with negation and return fast, without using guard: if name.characters.count == 0 {
    return nil;
    }
    ... // rest of code

    • Vince O’Sullivan

      Yes, you can do that and that works. The benefits of the guards statement are that you can use it as an escape clause with a positive test rather than a negative one (which tends to be more robust, particularly for complex tests) and also that it will unwrap optionals and make them available to the rest of the function without enclosing the rest of the function in an else clause.

      • tim

        “a positive test rather than a negative one (which tends to be more robust”

        I would love to see some data on this point. I could believe it, but I could just as easily believe the opposite.

  • JohnnyJoeIdaho

    Apple is both good and bad when it comes to being different. Objective-C was a perfect example and Swift still suffers the same problem. Why do they need to mess up casting, variable declarations, method calls and return types. It seems they believe that if they do it different than 99% of all other professional languages it means its better and special.

    Please Apple fire your staff who develops these languages.
    why not just have Int x = 3 rather than x:Int = 3…..I mean really is this some Pascal fanboys revisit of his past?

    • tim

      Out of all the criticisms of Swift, you’re taking issue with the order of keywords in declarations?

      It’s the same order as most other functional languages, like Haskell and OCaml. It’s the same order as most optionally-typed languages, like TypeScript, Python, or Scala. What 495 programming languages use C’s order?

      Considering Swift has type inference, it would be pretty weird if they used the same order as C.

  • tim

    I’m confused. The post started out talking about “guard” versus “if”, but then the “guard” example also gets to use “throw”, while the “if” example returns an optional, and then it descended into a comparison of “throw” versus optionals.

    Why do these methods implement different interfaces? You’re making “if” try to defend itself with both hands tied behind its back!

    • gerlot

      That is a very good point!

  • Santhosh

    func createPersonNoGuard() -> Person? {
    if let age = age, let name = name
    where name.characters.count > 0 && age.characters.count > 0
    {
    if let ageFormatted = Int(age) {
    return Person(name: name, age: ageFormatted)
    } else {
    return nil
    }
    } else {
    return nil
    }
    }

    Can be rewritten as
    func createPersonNoGuard() -> Person? {
    if let age = age, let name = name
    where name.characters.count > 0 && age.characters.count > 0 { } else {
    throw InputError.InputMissing
    }
    if let ageFormatted = Int(age) { } else {
    throw InputError.InputMissing
    }
    return Person(name: name, age: ageFormatted)
    }
    Which makes it similar to guard version except for the empty braces after ‘if’.
    And you also see the happy path.
    Now tell me what’s the big deal other than empty {} ??

  • Santhosh

    EDITED:
    func createPersonNoGuard() -> Person? {
    if let age = age, let name = name
    where name.characters.count > 0 && age.characters.count > 0
    {
    if let ageFormatted = Int(age) {
    return Person(name: name, age: ageFormatted)
    } else {
    return nil
    }
    } else {
    return nil
    }
    }

    Can be rewritten as
    func createPersonNoGuard() throws -> Person {
    if let age = age, let name = name
    where name.characters.count > 0 && age.characters.count > 0 { } else {
    throw InputError.InputMissing
    }
    if let ageFormatted = Int(age) { } else {
    throw InputError.InputMissing
    }
    return Person(name: name, age: ageFormatted)
    }
    Which makes it similar to guard version except for the empty braces after ‘if’.
    And you also see the happy path.
    Now tell me what’s the big deal other than empty {} ??

    • Vince O’Sullivan

      Well, one big deal is scope. In your example, the variable ageFormatted only exists within the if statement in which it is declared. The same is true for the age and name variables declared in the first if statement. None of those variables are in scope when the return statement is executed.

      With a guard statement, the variables declared in those guard statements are available to the rest of the function, even after the guard statement is complete.

      I recommend that you use a swift playground and see if you can get your example to compile.

  • Happa

    Here’s what I don’t get. “If” requires a positive test, and doesn’t require the block to exit the scope. “Guard” requires a negative test, and does require the block to exit.

    Why are these seemingly unrelated aspects connected? It’s not even like anything else in Swift’s syntax.

    I’ve written hundreds of thousands of lines of code in languages like Ruby and Lisp, which have “unless” (which takes a negative test like “guard”, but doesn’t require the block to exit scope). There’s zero correlation that I’ve seen between using “unless” and exiting scope, in either direction.

    I wish I had each of these features separately in Swift. I can’t count the number of times I’ve had to write, in Swift, “if !(…big expression…)” when I really just wanted “unless”. Or the number of times I’ve wanted to exit the scope if something fails, but had to write it “guard !(…)” because the natural test was backwards.

    I’d be much happier if “unless” were simply the opposite of “if”, and Swift let me prefix either one with something to indicate that its block must exit the scope. This 50% solution we have feels arbitrary and clumsy.