I’m writing a bit of Kotlin / Okio / Okhttp that d...
# getting-started
a
I’m writing a bit of Kotlin / Okio / Okhttp that downloads to a temporary file then renames it. Lots of things can go wrong, obviously, being I/O … http errors, network errors, insufficient space on storage, storage volume missing, etc … but when I look at the Okio function signatures I really just see that it throws “IOException”. I know Kotlin doesn’t have checked exceptions, but if I want to present different UI options to the user (clean disk space, etc) how can I know what exact exception subclasses can be thrown when I call that function? I was hoping there was some static analysis tooling like “what throws from here” but I don’t see that.
1
j
This is exactly what tests are for. It doesn't matter how the library is documented to work, it's how it actually works that matters. Set up conditions that mimic what you are interested in, and ensure your code handles them. This can be easier or harder depending on the design of the library... some are not designed to be testable, so are not.
☝🏻 1
l
To be fair, it would be nice to be able to enforce the caller to deal with specific exceptions. I have an internal API where it's absolutely critical that exceptions are handled correctly, and if not, you get subtly wrong data because the wrong level handles the exception. Checked exception would prevent the caller from forgetting to handle it.
But it is what it is.
a
Errors as values is the answer
l
@Arjan van Wieringen not in this case. It's a very low-level function performing scalar maths operations on 64-bit integers.
Wrapping the result in an object has a 30% or so performance hit, so I use an exception when the result overflows 64 bits (which is extremely rare). The caller is responsible for catching this exception, extracting the BigInt result, and then take an alternative path to compute the result of the result using bigint arithmetic.
This is extremely specific, and not something most developers have to worry about. Specifically, this is deep inside a runtime interpreter for a programming language.
And since I wouldn't mind hearing opinions on better ways to handle it, I'm sharing some example code to show how this is done. Specifically, this code must catch
LongExpressionOverflow
, pull the correct result out of the exception and then perform the operation using bigints and rethrow a new
LongExceptionOverflow
with the result. Imagine what happens if one were to forget this, not the caller of this function would still get that exception, but the content would be wrong, and there appears to be no way to get the type system to warn me about this.
a
@loke i wasnt responding to you but to the OP
c
Wrapping the result in an object has a 30% or so performance hit, so I use an exception when the result overflows 64 bits (which is extremely rare). The caller is responsible for catching this exception, extracting the BigInt result, and then take an alternative path to compute the result of the result using bigint arithmetic.
Take a look at #C5UPMM0A0’s
Raise
DSL. It requires context parameters, but it looks like they will be stable in a few months. It has the same usability than errors-as-values but doesn't use wrapping, so there is no performance impact on the happy-path.
l
@CLOVIS thank you. This looks like something that could be really useful.
@CLOVIS do you happen to have a link to the DSL feature?
(internally, the failure path is an exception without stacktrace, which is not free but still a lot less expensive than a true exception; the main benefit is no overhead in the happy path)