Swift's guard
statement is awesome for early exits. In some scenarios, we might want to perform one call besides exiting using return
.
final class AppCoordinator {
func showApplePaySplash() -> Void { /* some presentation logic */ }
}
final class OnboardingCoordinator {
init(settings: Settings, parent: AppCoordinator) {
// This code should probably use a `switch` statement and not `guard`, but I am curious about this
guard settings.hasSeenApplePaySplash else {
parent.showApplePaySplash() // method returning `Void`
return
}
// Some more logic...
}
}
What I am curious about is if it is possible to shorten the syntax:
guard settings.hasSeenApplePaySplash else {
parent.showApplePaySplash()
return
}
Since this is inside an init
we cannot write:
guard settings.hasSeenApplePaySplash else {
return parent.showApplePaySplash() // compilation error: `'nil' is the only return value permitted in an initializer`
}
We can change the four lines to this oneliner of course:
guard settings.hasSeenApplePaySplash else { parent.showApplePaySplash(); return }
Which reads out quite nicely IMHO. But I still would like to get rid of that return
(because I am curious if it is possible. No need to tell me: "just use return man").
In this other scenario, where we would like to guard
against some undefined bad behavior/state:
guard index < myArray.count else { fatalError("Array out of bounds exception, did you think about X, Y, Z?") }
We do not need to write return
, since the method fatalError
returns the specific type called Never
.
Note: code below this point is just experimental driven by curiosity since it is bad Swift code:
So if we could change the signature of:
func showApplePaySplash() -> Void
to use Never
, like so:
func showApplePaySplash() -> Never
Then we could replace:
guard settings.hasSeenApplePaySplash else { parent.showApplePaySplash(); return }
This is what I'm curious about, once again, not preferred or endorsed: With just:
guard settings.hasSeenApplePaySplash else { parent.showApplePaySplash() }
But Never
does not have any initializer. And it seems like the only possibility of creating a Never
is to use methods such as fatalError
to create a crash.
I found this execellent SO answer by @guy-daher - making it possible to replace fatalError
making it possible to "catch" it in tests. But it uses waitForExpectations(timeout: 0.1)
which is not possible outside of test suites?
So Never
is probably of no help here. Pre Swift 4 (pre Swift 3?) there was function annotation called @noreturn
that seemed like it could have helped?
Is there any way of achieving this? :)