Throwable is an open hierarchy where you may catch more than you originally intended to Costly to create. Throwable#fillInStackTrace attempts to gather all stack information to present you with a meaningful stacktrace ref: http://normanmaurer.me/blog/2013/11/09/The-hidden-performance-costs-of-instantiating-Throwables
considered generally a poor choice in FP when - Modeling absence - Modeling known business cases that result in alternate paths - Used in async boundaries over APIs (callbacks) But of course you can still have exceptions when you try to access servers that are down or files that are missing
Java Λrrow (0.11.0) is a library for Typed Functional Programming in Kotlin Λrrow includes the most popular data types, type classes and abstractions such Option, Either, IO, Functor, Applicative, Monad Ref: https://arrow-kt.io/
abstract interface, that simply defines a way of composing data When data type supports composition (flatMap), that's pretty much everything that is needed to wear the "monad badge"
tries to solve the problem with Null-safety based on ? (not functional) Modeling the absence of values through Option (Scala, Haskell) When Option type is used, consumer will be forced to handle the case of absent value Λrrow provides a Monad instance for Option
either a Left value or a Right value Good substitute for BusinessException Λrrow provides a Monad instance for Either in the same way it did for Option When computing over Either, whenever a Left value is found, the computation short-circuits
problem, Kotlin language introduced Coroutines Javascript generators (async/await), Continuation (Java/Loom) Using coroutines, Λrrow provides a specialization that enables readable async/ await style code for any Monad Internally, Monad#flatMap is used for chaining Same as for comprehension in Scala
ListK, SetK, MapK Monad comprehension over Flux/Mono (FluxK/MonoK) Monad comprehension over Rx (ObservableK) What if Rx + Either ? Oh shoot, it sounds complicated !
we may end up with nested structures such Monad Transformers can help us to reduce this boilerplate Cats / ScalaZ (Scala) Monad Transformers enable you to combine two monads into a super monad
OptionT<F, A> Any monad F surrounding an Option<A>, we can obtain an OptionT<F, A> So our specialization OptionT<ForMonoK, String> is the OptionT transformer around values that are of MonoK<Option<String>>.
EitherT<F, L, A> Any monad F surrounding an Either<L, A>, we can obtain an EitherT<F, L, A> So our specialization EitherT<ForMonoK, BookingError, A> is the EitherT transformer around values that are of MonoK<Either<BookingError, A>>.
1.5x faster than EitherT for short tasks For long tasks, the differences are probably too small (~10%) to make any practical difference unless performance is your main concern. In that case, stay away from this combination. Ref: https://www.iteratorshq.com/blog/benchmarking-functional-error-handling-in-scala/ Method ns/op (tf = 2) ns/op (tf = 5) ns/op (tf = 100) ns/op (tf = 200) EitherT 9681 (+- 14) 9871 (+- 8) 29288 (+- 41) 48674 (+- 99) Future[Either[…]] 6443 (+- 11) 6775 (+- 21) 26657 (+- 42) 45970 (+- 66)
? For me Exceptions are for lazy people (I’ll deal with it later , or may be never...) Faults and errors happens all the time, make your system more fault tolerant The more your code is explicit, the easier for others to maintain it