somu
(somu)
1
Overview:
I have a function which accepts Error? as a parameter.
I would like to check if there is an error I would like to handle the error, if there is no error I would like to do some processing.
Question
- What is the preferred approach (it need not be one of the 3 that I have mentioned).?
I have mentioned below 3 approaches that I could think of, was wondering if there was a better way to handle it.
Code
func f1(error: Error?) {
//Gaurd is more expressive of the intent but end up having to force unwrap
guard error == nil else {
print("Error: \(error!)") //Forced unwrapping
return
}
print("start processing")
}
func f2(error: Error?) {
//Intent is not as clear as the guard statement, but no force unwrapping
if let error = error {
print("Error: \(error)")
return
}
print("start processing")
}
func f3(error: Error?) {
switch error {
case .none:
print("start processing")
//This is ok but all the processing code would be embeded with in the case
case .some(let errorExists):
print("Error: \(errorExists)")
}
}
1 Like
I believe the preferred and 'swifty' approach is not digging into the optional – either the first or second, further it is a matter of style. Force-unwrapping in the body of the guard statement is absolutely safe since you know it isn't nil, but not necessary:
guard error == nil else {
print("Error: ", error)
return
}
1 Like
somu
(somu)
3
Thanks @anthonylatsis, I understand from your reply that the 1st or the 2nd approach is fine and that force unwrapping is fine with in body of the guard statement.
preferred and ‘swifty’ approach is not digging into the optional
Did you mean unwrapping when you mentioned "digging" ?
By digging into an optional I meant
let foo: T?
switch foo {
case .none: ...
case .some(let T): ...
}
Well, you could call that explicit unwrapping :)
somu
(somu)
5
Cool, thanks for clarifying
This shouldn't be preferred at all in this situation. Furthermore you ignore that error is still optional and the compiler will emit a warning when you pass an optional value to print. (Or have you missed the force unwrap? But I still discourage you from writing code like this even though it's true that you're safe to force unwrap there.)
I think the cleanest solution here is to unwrap it and return from the main function or proceed otherwise.
func f2(error: Error?) {
if let error = error {
return print("Error: \(error)")
}
print("start processing")
}
So f2 is the way to go here. I also would consider f3 as good enough but that depends on the nested scopes that will follow in the real wold use case (avoid pyramid of doom).
1 Like
I would too go with f2, but you know, passing an optional to print never hurt a fly. I didn't say it is preferred: I mentioned it isn't necessary (unwrapping to print).
Sorry I misjudged too quickly by the example. ;)
Personally I hate force unwarps even if in theory you can use them in a 'safe' manner, but this is just a wrong habit IMO.
Here is one example of a library we have to use in our project, but I'm so freaking scared to touch it because internally they abuse force unwraps to the max.
somu
(somu)
9
Thanks @DevAndArtist and @anthonylatsis. Really nice to hear the different views.
Presently I am using f2, the problem that I encountered with guard is that accidentally if I added another condition then I might be in trouble.
Example:
guard error == nil,
a == 10 else { //assuming a is also a parameter and needed to check before processing
print("Error: \(error!)") //Here error was nil and it crashed
return
}
2 Likes
@DevAndArtist If it's a habit – sure.
DeFrenZ
(Davide De Franceschi)
11
I think it's a great question and one that doesn't really have an answer
I personally prefer f2, or for something slightly more complex than an Optional (e.g. Result) I go with f3 if I need to handle more than one case.
Also in the f3 case I'd go with the "error" case first, to follow the "bail out early" style of writing code.
1 Like
somu
(somu)
12
Thanks @DeFrenZ, looks like f2 is the way to go for now for simple scenarios.
I also like the way you mentioned to have error case first in f3 to bail out first similar to what we do in guard. That's a nice touch.