Has anyone thought about how Arrow could help with...
# arrow
j
Has anyone thought about how Arrow could help with the issue of unchecked exceptions? Even though the design of Arrow is meant for domain errors, in the real world the line gets quite blurry, I have noticed that a lot of projects that use arrow end up catching exceptions and converting them into Eithers, even the "best practices" example from the Arrow docs has this issue: https://github.com/nomisRev/ktor-arrow-example. I really like the idea in ZIO/effect.ts of having the ability to choose how you want to handle those types of IO exceptions. Would safe wrappers for ktor client/server, kotlinx serialization and SQLDelight or sqlc be too unidiomatic for Kotlin?
p
Most cases of "catching exceptions and converting them into Eithers" should be handling expected domain-related exceptions and converting them to the domain errors, and otherwise letting them propagate. The
ktor-arrow-example
shows this in a few places, i.e.:
Copy code
return Either.catchOrThrow<PSQLException, UserId> {
          usersQueries.create(salt, key, username, email)
        }
        .mapLeft { psqlException ->
          if (psqlException.sqlState == PSQLState.UNIQUE_VIOLATION.state)
            UsernameAlreadyExists(username)
          else throw psqlException // <-- if we haven't handled the exception as a domain error, propagate it
        }
j
That is exactly the problem I am talking about
y
Idiomatic safe wrappers should be possible using
Raise
and contexts. There is an emerging philosophy though of letting exceptions be for truly exceptional situations. These best practices are basically us Arrow users realising that an exception should have been a domain error. This is a good pragmatic way to deal with it. In a way, we're building mini-wrappers for those libraries in our code.
j
Having to manage all of your exceptions comes with huge mental overhead, comparable to lack of null safety in Java. Of course a big part of this issue is that legacy APIs often expose what should have been values as exceptions, but it is also often the case that something being a domain error depends on the context, not the type. If we had standard safe wrappers for ktor and sql, you could choose if something is exceptional or not depending on your needs, by using the appropriate raise context. Kotlin libraries like ktor often lack documentation on what exceptions they can throw on utility/helper methods, so you usually need to dig deep into the libraries to even know all of the modes of failure to correctly handle them