There are times, especially when handling special cases inside a function, that I would like to perform an action if a let statement evaluates to false and then continue with the normal code flow. Essentially it's a guard-let without a return or an if-let-else with an empty top block. I could logically negate a guard statement and put it in an if, but I can't negate an if-let. Here's an ugly example of code that isn't as clean as I'd like:
struct State {
let result: SomeResult?
}
func updateState() {
let currentState = computeState()
guard let lastPosted, lastPosted.result == currentState.result else {
currentState.post()
lastPosted = currentState
currentState.cleanUp()
return
}
currentState.cleanUp()
}
As you can see I want to ensure something is posted the first time updateState() is called even if State.result is nil, so I use a guard-let that fails if lastPosted is nil. But using guard means I have to return from inside the let, so my cleanUp() call is duplicated in each return path. This is just an example, you can imagine cases in which there is a lot more code that I would like to run either way.
One way to achieve this is to use an if statement:
func updateState() {
let currentState = computeState()
if lastPosted == nil || lastPosted!.result != currentState.result {
currentState.post()
lastPosted = currentState
}
currentState.cleanUp()
}
but that means I can't use if-let and I need to force-unwrap lastPosted which I don't like doing.
I could add an empty block to the if and do my work in the else:
func updateState() {
let currentState = computeState()
if let lastPosted, lastPosted.result == currentState.result {} else {
currentState.post()
lastPosted = currentState
}
currentState.cleanUp()
}
but that really doesn't read cleanly - it looks backwards until you notice the 'else' at the end of the if-let line.
Things could get really complicated with a private error or state enum or do/catch blocks. What I would really like is to simply make an assertion, perform an action if it fails, and move right along with the rest of my func:
func updateState() {
let currentState = computeState()
assert let lastPosted, lastPosted.result == currentState.result else {
currentState.post()
lastPosted = currentState
}
currentState.cleanUp()
}
Unfortunately 'assert' has a connotation which might cause some to question whether or not the code is compiled in a release build so I'm open to other terms or other thoughts on making the original guard cleaner with the existing language. Thanks.