dave08
01/22/2018, 8:12 AMuserRepo.getUser(userId)
and it wasn't found, should it return null, throw a domain exception (NoUserFoundException) or have a sealed class with a null object? (I'm using coroutines, not Rx...)spand
01/22/2018, 8:17 AMCzar
01/22/2018, 8:20 AMfun getUser(id: YourIdType): User?
and you return null
when User can't be found; if the caller can be Java, I'd go with Optional<User>
return type. Throw is bad practice here, because you're forcing try/catch semantics when your caller might be okay with not finding a user.requireUser/findUser
or whatever you call these two methods, but this seems superfluous to me, as it just complicates the API. If you're not working in an extremely performance-constrained environment a simple null/optional check of a return value should not be an issue and simpler approach (one less method) wins in my book.spand
01/22/2018, 8:30 AMCzar
01/22/2018, 8:41 AM?: error("")
is something you'll find yourself writing more often than (?.let {}
), then by all means get/find
(where get
throws and find
returns null
) is indeed a better approach. I'm probably just a bit biased due to the latest project I worked on, which didn't have many ?: error("")
situations, if something wasn't found it didn't mean an error has happened. 🙂dave08
01/22/2018, 8:52 AMCzar
01/22/2018, 8:56 AMAndreas Sinz
01/22/2018, 9:25 AMdave08
01/22/2018, 10:18 AMcedric
01/22/2018, 2:48 PMnull
, I've seen findUser()/findUserNoThrow()
or findUser()/findUserOrNull()
. This is more useful in libraries where you want to give your users options.dave08
01/22/2018, 3:30 PMcedric
01/22/2018, 3:31 PMraulraja
01/22/2018, 8:54 PM?
or Option
to denote User not found if you want to remain exception free. Does it have the same semantics to not actually finding the user to say the network is down?
I'd model the exceptional known cases in an ADT and return a disjunction of a known error case or the actual value:
sealed class ApiError
object NetworkFailure: ApiError()
data class UserNotFound(val id: String): ApiError()
fun findUser(): Deferred<Either<ApiError, User>> = TODO()
You loose valuable types and semantics when modeling known cases with just ?
or Option
and you may need those down the road to display appropriate error messages or branch out biz logic into the unhappy path.
If you are interested in an FP approach to error handling more info here: http://arrow-kt.io/docs/patterns/error_handling/tschuchort
01/22/2018, 9:03 PMMaybe
. I prefer nullable types for non-rx functions because they're nicer to use. ?.
is like Maybe.flatMap
anywaycedric
01/22/2018, 9:07 PMdave08
01/22/2018, 10:46 PMcedric
01/22/2018, 10:48 PMraulraja
01/22/2018, 10:54 PMwhen
over a sealed class hierarchy).
An example of pure and total functions are:
fun add(a: Int, b: Int): Int = a + b
And example of an impure one:
var x: Int = 0
fun addToX(a: Int): Int = x = x + a
var x: Int = 0
fun addToX(a: Int): Int = x = if (a > 0) x + a else throw IllegalArgumentException("value expected to be positive")
dave08
01/22/2018, 10:58 PMreturn
in the middle of fun
logic? Also, even exceptions can be unit tested...? @raulraja You still needed to use an external var x
to make it impure, the exception didn't do it, did it?raulraja
01/22/2018, 10:58 PMcedric
01/22/2018, 10:59 PMF => T
, you will typically think “It’s a function that takes a parameter of type F
and returns a parameter of type T
. Here is the cool part: now read this from a mathematical eye and you’ll read “F implies T”. There is actually a mathematical equivalence between these two interpretations: they are strictly equivalent according to a theorem that was proven decades ago.raulraja
01/22/2018, 10:59 PMdave08
01/22/2018, 11:01 PMraulraja
01/22/2018, 11:02 PMcedric
01/22/2018, 11:02 PMraulraja
01/22/2018, 11:03 PMfun printLater(): () -> Unit = { println("Hello pure") }
cedric
01/22/2018, 11:04 PMraulraja
01/22/2018, 11:04 PMpure
because printLater
performs no effects, it just returns a function that does.dave08
01/22/2018, 11:07 PMcedric
01/22/2018, 11:08 PMraulraja
01/22/2018, 11:13 PMcedric
01/22/2018, 11:13 PMdave08
01/22/2018, 11:15 PMfun
, but rather for total fun
?raulraja
01/22/2018, 11:15 PM@Throws
exceptions right?cedric
01/22/2018, 11:16 PMraulraja
01/22/2018, 11:17 PMtschuchort
01/22/2018, 11:22 PMcedric
01/22/2018, 11:23 PMEither
, the compiler will only keep you honest if quite a few conditions are met (sealed type, using when, etc…). Still plenty of opportunities to ignore the error part of Either
.dave08
01/22/2018, 11:24 PMcedric
01/22/2018, 11:25 PMdave08
01/22/2018, 11:27 PMraulraja
01/22/2018, 11:29 PMcedric
01/22/2018, 11:30 PMraulraja
01/22/2018, 11:32 PMcedric
01/22/2018, 11:33 PMraulraja
01/22/2018, 11:37 PM