I just got tripped up by this unexpected outcome of type inference, and wanted to share it.
enum
that makes sense for our project.
enum Coverage {
case All
case Partial
case None
}
enum
as an argument. But, let's make it Optional
so that the caller can omit it to use a default value.
/// - parameter covering: If `nil`, use the default coverage.
func applyPaint(covering coverage: Coverage? = nil) {
if let coverage = coverage {
print("covering: \(coverage)")
}
else {
print("got nil; using default coverage")
}
}
applyPaint(covering: .All)
applyPaint(covering: .Partial)
applyPaint(covering: .None)
Wait, what happened in that last one, with .None
?? We passed a non-nil value, but it's acting like it got nil!
Well, remember that an Optional
is actually an enum
:
enum Optional<Wrapped> {
case None
case Some(Wrapped)
}
And that nil
is just syntactic sugar for Optional.None
. So, the compiler's type inference is assuming that we meant Optional.None
, instead of Coverage.None
. Facepalm!
Solutions
There are some simple ways to avoid this issue.
We can just pass the full enum name as the argument when calling our function.
But, that means we need to remember to do that in all cases that might call this, which feels very error-prone.
applyPaint(covering: Coverage.None)
enum Coverage {
case Everything
case Partial
case Nothing
}
applyPaint(covering: .Nothing)
Notes
I've filed this as SR-2176.
Thanks
As usual, thanks to Jacob for helping me figure out this fun mishap.