is there a better way to return an error inside an...
# arrow
j
is there a better way to return an error inside an
either
block than using
shift
? this is my case
Copy code
either {
    val data = dao.getData(externalReference) ?: shift(Error.NoData)
    ...
}
I could make a new function that return a
Either<Error.NoData, Data>
and then use
bind
but then I need to pass parameters along and all and I end up with 5 or 6 lines for just 1 line that is actually interesting. It would be nice to have a
or
functions or something like that as an extension
c
I'm sorry, I don't understand your question. Your example doesn't use
switch
.
j
True, i meant
shift
not
switch
in the question
c
You can write:
Copy code
val data = dao.getData(externalReference)
ensureNotNull(data) { Error.NoData }
Also,
shift
is called
raise
now 🙂
👍🏻 1
j
my project still uses version 1.1.5 i think, that might be why it’s still shift for me
c
Yes it is, the rename was in 1.2.0
I recommend making the switch as soon as possible, a lot of stuff has been renamed
also there's
recover
and
mapErrors
now, I don't know how we ever wrote code without them lol
y
If you're willing to use context receivers, which I can understand you might not be since they're not stable yet, you can change your dao definition:
Copy code
context(Raise<Error.NoData>)
fun Dao.getData(externalReference: ExternalReference) = getDataSomehow(externalReference) ?: raise(Error.NoData)
s
I personally prefer
ensureNotNull
over
?:
, even when using
context(Raise<Error.NoData>)
. It's one of the few places I prefer a DSL function instead of Kotlin language feature, but I find it so similar to
requireNotNull
that it feels idiomatic to me.
1
y
Also, the design for
SingletonRaise
is being worked out right now, but when that's done, you'll be able to declare a block that allows you to do
ensureNotNull(data)
and
data.bind()
with the fallback value pre-decided. That'd allow you to call many functions that can fail where failing doesn't have a meaningful value. I think when that design is fledged out (it won't be before Arrow 2 because there's breaking changes involved) and accepted, this use case would get much simpler
s
How is that @Youssef Shoaib [MOD]? That seems kind-of dangerous to use in this case, because it might swallow errors.
y
@simon.vergauwen It's an explicit scope
SingletonRaise
that is intended to unify the APIs of
nullable
,
option
, and
ignoreErrors
. Its usage here would be similar to
withError
, but introducing a
SingletonRaise
instance instead that has a no-arg
raise
method alongside
ensureNotNull(foo)
and
Option.bind()
and any other "methods that fail with a meaningless value" It's very much in the works, but it'd look something like:
Copy code
either {
  withSingletonError({ Error.NoData }) {
    // Can bind nullable inside:
    val data = dao.getData(...).bind()
    // Can write ensure with no error specified:
    ensure(data is Bar)
    data.barMethod() // smart casts should work accordingly I think 
  }
}
If you want, it's practically
option(block).getOrElse { raise(error()) }
I realise while writing this that this particular method isn't in the PR just yet 😅. It's a rather natural extension though, and amounts to perhaps 2-3 lines
👀 1
j
Well back to my case, the “…” refers to other methods raising other subclasses of
Error
. I guess
withSingletonError
wouldn’t fit there
y
It would work just fine! When raising any other errors, the `either`'s receiver would take over. This means that you both get to
bind()
nullable things and
ensure
without an error specified, and at the same time you can raise any other errors you want, and the
either
would deal with them. Maybe you'd need to massage the compiler by specifying the
either
type params, but otherwise everything works fine I believe.