
Typesafe Error Handling in Kotlin - veiset
https://kotlin.christmas/2019/17
======
mamcx
One of the most use-full things of Rust is to have a clear "conversion" trait:

[https://doc.rust-lang.org/std/convert/trait.From.html](https://doc.rust-
lang.org/std/convert/trait.From.html)

This is my #1 thing with rust.

Is a stroke of genius to have a clear API for make conversions.

~~~
vmchale
Is there any writeup of the theory behind this? I'm particularly interested in
type inference.

~~~
killercup
The RFC for adding `?` to the language might be a good start: [https://rust-
lang.github.io/rfcs/0243-trait-based-exception-...](https://rust-
lang.github.io/rfcs/0243-trait-based-exception-handling.html)

------
joostdevries
The monadic approach to exceptions like it's done here has the downside of
having to encode all your business logic in maps and flatmaps. All the
intermediary functions will have to return Try. And all the Try values have to
combined into one. That type fidding code feels like cruft that doesn't add
much value.

And I say that having developed in Scala for years and years.

Of course there's still sometimes when you want processing of other items to
proceed, even though this one has failed. And that's where Try is really
essential. So that's where we use it only: at the topmost level.

It's only at that top level that we wrap the call in a Try. And that works
rather well.

One reason to do it like this is that we want to leverage the design
philosophy of Kotlin. And not be writing Scala or Haskell in Kotlin _). And
Kotlins philosophy when it comes to exceptions turns out to be: exceptions.
Which is apparent in Kotlin coroutines, channels and flows.

_ ) that's also why we try to stay away from Arrow

~~~
ragnese
Definitely fair points. I do feel like I'm swimming upstream even when I'm
using the built in Result class in Kotlin.

Truth is, I rather be writing Rust, but I need the JVM sometimes. ;)

------
benol
It's worth pointing out that Kotlin's standard library contains a type called
`Result` with a slightly different API. Also a function called
`runCatching`[1] that uses it.

[1] [https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/run-
catc...](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/run-
catching.html#runcatching)

------
manojlds
What are these .Christmas TLDs? Seeing those crop up and only makes sense at
this time of the year right?

~~~
outadoc
[https://blogg.bekk.no/introducing-bekk-christmas-
ad01660ccad...](https://blogg.bekk.no/introducing-bekk-christmas-ad01660ccadf)

------
RivieraKid
Honestly, I prefer to have the option of using checked exceptions, it's often
leads to better readability than using Result. This is my main issue with
Kotlin.

~~~
ragnese
I feel like I'm the only crazy person who thinks checked exceptions are better
than unchecked exceptions. I've read all the arguments against them and they
just don't resonate with me. "Oh. So you think it's okay that a dependency's
method changed to throw a new exception, but you don't want to have to change
your code? Sounds super lazy and risky to me..." When your dependency's logic
changes, yours probably needs to, as well.

What really drives me nuts is when the same person shits on checked exceptions
and then advocates for using a monadic return value. They're completely
isomorphic. The only difference is in how it reads.

~~~
lenkite
Java is the only language that has checked exceptions AFAIK.

Checked exceptions just lead to interface pollution. You _really_ don't know
what type of exception can be thrown by an implementation of a facade when you
are defining the facade. And so then you are forced to define a
_InterfaceOperationException_ and then force all callers to wrap their
exceptions in this type. Even if you use an implementation that is exception-
free, you are forced to catch.

Painful and elaborate ceremony for very little gain. Usually exception
handling is centralised at a few places in the code. Catching exceptions at
these areas and boundaries is the _best_ place instead of littering handler
code all over the code base.

Oracle has realised that checked exceptions are a mistake. None of the java
functional interfaces declare checked exceptions. If your operation throws a
checked exception, it _cannot_ be used as a convenient method reference
lambda. It does not _decay_ into a standard functional interface. This alone
is an ultra critical-strike against checked exceptions.

If a condition is _so_ important that you need to declare it as a checked
exception, it generally indicates it should have been be a return type or your
functional granularity is large. And normal types, unlike exception types, are
well-suited to generics.

~~~
RivieraKid
Swift does have checked exceptions too (at least by my understanding of the
term "checked exception"). In general I think Swift is more thoughtfully and
elegantly designed than Kotlin, people usually say that they're very similar
but I find Swift more pleasant read and write.

~~~
ragnese
Yes and no. In Swift you have to mark if a function throws, but not WHAT the
function throws.

The Java-style checked exception haters might see that as the best of all
worlds.

I generally agree that Swift is a little nicer than Kotlin. I like the enums
better than sealed classes, I like that Swift has value types.

The only think from Kotlin that I miss in Swift is the scoping methods: apply,
with, let, also.

------
ragnese
I'm a little confused by something. I wouldn't have expected his/her example
code to compile:

    
    
      fun divide(dividend: Int, divisor: Int): Try<Int, String> =
          when (divisor) {
              0 -> Try.Err("Cannot divide by zero!")
              else -> Try.Ok(dividend / divisor)
          }
    

The first branch of `when` is of type `Try<Nothing, String>`, the second
branch is `Try<Int, Nothing>`, and the return value is supposed to be
`Try<Int, String>`. None of those line up...

How is that possible? Does the compiler do some magic for the `Nothing` type?
The definition looks pretty damn simple:

    
    
      public class Nothing private constructor()

~~~
greiskul
It's not possible in Kotlin to have an instance of Nothing, and the compiler
does some magic for the Nothing type, in that it can be converted to any other
type in the system (so it's like the opposite of the Any type). This allow
code patterns like:

''' val personName = person.name ?: throw IllegalArgumentException("Name
required") '''

Where the type of personName is now String, cause if name was null it would
throw an exception (and the type of a throw expression is Nothing).

------
UserIsUnused
Why not just use sealed classes for your given use-case rather than a generic
result? If you want to do generic why not go full Either?

~~~
mrkeen
Maybe the people that realise that are the people who self-select into a
language where Result and Either are just implementation details and should be
hidden behind F[_] or similar.

------
jbverschoor
Ah right another thing copied from swift.

~~~
UK-Al05
It's actually a fairly old method, that's recently gained popularity as
functional programming interest increases.

~~~
vmchale
I think monadic do comes from Haskell and its ancestors.

