If we want to say, "use this or if it's nil
, that default", we can write:
let a = maybeA ?? A()
However, saying "use this or if it's nil
, throw" is more verbose (if descriptive):
guard let a = maybeA else {
throw SomeError()
}
One might imagine writing
let a = maybeA ?? throw SomeError()
but this doesn't work: throw X
is a statement, not an expression, so it doesn't parse. As @Nevin notes, we can make the right-hand side an explicit closure evaluation:
let a = try maybeA() ?? { throw SomeError() }()
This reads a little arcane, and the try
feels both redundant and oddly placed.
Further, @Chris_Lattner3 comments:
That said, making that change wouldn't fix your code above, because ?? requires the left and right side to be the same base types, and Never is not an A.
This is a little odd -- arguably, Never
is a natural candidate for a bottom type; see here -- but prevents us from just definining throw X
to be an expression of type Never.
What are other ways to express the above neatly?
For reference, this is valid Kotlin:
fun foo(a: String?) : Int {
return a?.toIntOrNull() ?: throw RuntimeException()
}
Kotlin's Elvis operator is similar to ??
, but (I think) throw X
is an expression of type Nothing
here, which is the bottom type in Kotlin. So this type-checks (and even drives data flow analysis).