Friday, March 25, 2016

Swift: Guard ... what?????

At first I saw guard code sample, and I was like WHATT? WHY????

See in C++  there is only if (x) or if(!x) where x being an expression that can contain more than one expression in itself. So pardon me when I say WHY?????

Then after googling I found some nice articles, which explain why and when guard could be used efficiently.


So here goes my understanding:

Basically Guard is like If conditional statement except, it enters its scoped block only if the condition is false.

if guard x = x else { return; }

The code block inside else should either be a function that does not return anything, or it should move the control of execution outside the guard statement's code block. Meaning, only return/break/continue/throw can be used. Also one of these should be used otherwise be ready to face the compiler wrath with "/path/GameScene.swift:55:3: 'guard' body may not fall through, consider using 'return' or 'break' to exit the scope"

But why? Why can't I do if let x != nill { return; } ? This and the guard seems to be exactly the same.
Here is where nuances of the language comes into play.

Here are a few pointers regarding guard. I am going to list that out for you here.

1. Automatic unwrap of the optional 
If x is not nil, that is if x is valid, then if you use IF statement, then you would have to force unwrap it everytime after the IF statement using x!.function();

But if you use guard, then you need not force unwrap it, and can use it as a non optional parameter as x.function(); because guard preserves the context of x. Keeps it intact.

Say What????

So this would mean, when you use guard, you need not force unwrap the non optional parameter with !, but guard does that for you when exiting its scope. Which some people perceive as fine, and some not.

For e.g

var lastTick: NSTimeInterval? = 0


void update(){
     guard lastTick = lastTick where lastTick > 0 else {
        return;
    }

   lastTick.advanceBy(5); //automatically unwrapped by guard if exits, for you. How convenient and intuitive. Because if it was null, it would have returned from the function.
}

2. Guard is more like a graceful assert
Since guard scoped block executes only if the condition is not true, it can be looked upon as an assert, but instead of asserting, it would gracefully exit.

3. You need not check for the NOT condition. 
Yes that is a convenience. Instead of doing if (!x) you can do guard x.
for e.g 

var previousDate: NSDate?;


void update()
{
    guard let previousDate = previousDate else{
        return;
    }
}

In this, the condition which should be true is clearly evident to the same programmer after many years, or to a different programmer the same day.
     
4. Also to keep the code clean, instead of using nested conditions with if, you can guard them individually and exit from the scope if not met

Normally when lots of conditions have to be met as pre-checks in order for a code inside a function to run, it seems cleaner to do a guard for each, and exit from scope if not met.

This is the same as "Designed by Contract" software design terminology, that states all the preconditions have to be met before the main block of module could be executed.

Note: 
As an added bonus (I am kidding ofcourse) you can use guard on non optional values as well.

Thanks for reading this write up.


No comments: