The Power of Guard

Here’s a guard statement with many different kinds of features by Benedikt Terhechte:

guard let messageids = overview.headers["message-id"],
    messageid = messageids.first,
    case .MessageId(_, let msgid) = messageid
    where msgid == self.originalMessageID
    else { return print("Unknown Message-ID:", overview) }

I love guard statements. It helps make code much more readable and keep methods un-intended.

I feel less amorous about guard-case and if-case matching, though:

if case .Fruit = foodType { ... }

This reads an awful lot like Yoda conditions where you place the constant portion on the left side. This isn’t even a typical boolean test (which would use the equality operator ==) but a failable assignment (=). I can force myself to read and write it this way, but it always feels backward to me. It took me quite a while to memorize this, which I found surprising, as it was comparatively easy to learn Swift in the first place.

Apart from the guard-case portion, the example contains your standard guard-let unwrapping. The else clause is special though, and I didn’t know this would work:

guard someCondition else { return print("a problem") }

When the function is of return type Void, you can return a call to another void function. This is shorter than splitting these two instructions on two lines, but it’s too clever for every reader to understand. print("a problem"); return is just as compact, as Terhechte points out.

Using Guard in Unit Tests

I have just discovered how cool the new guard statement is to keep unit tests lean and shallow – avoiding if-let nesting, that is. Update 2021-05-11: Modern XCTUnwrap is even better. Consider this test case: There are two optionals I have to deal with. That’s why I throw in assertions to cover problems. I don’t want to assert anything new here, though: the test helper soleFile() is valdiated in another test case already. But I need some kind of failure in case the Core Data test case goes nuts.

Continue reading …