https://kotlinlang.org logo
Docs
Join the conversationJoin Slack
Channels
100daysofcode
100daysofkotlin
100daysofkotlin-2021
advent-of-code
aem
ai
alexa
algeria
algolialibraries
amsterdam
android
android-architecture
android-databinding
android-studio
androidgithubprojects
androidthings
androidx
androidx-xprocessing
anime
anko
announcements
apollo-kotlin
appintro
arabic
argentina
arkenv
arksemdevteam
armenia
arrow
arrow-contributors
arrow-meta
ass
atlanta
atm17
atrium
austin
australia
austria
awesome-kotlin
ballast
bangladesh
barcelona
bayarea
bazel
beepiz-libraries
belgium
berlin
big-data
books
boston
brazil
brikk
budapest
build
build-tools
bulgaria
bydgoszcz
cambodia
canada
carrat
carrat-dev
carrat-feed
chicago
chile
china
chucker
cincinnati-user-group
cli
clikt
cloudfoundry
cn
cobalt
code-coverage
codeforces
codemash-precompiler
codereview
codingame
codingconventions
coimbatore
collaborations
colombia
colorado
communities
competitive-programming
competitivecoding
compiler
compose
compose-android
compose-desktop
compose-hiring
compose-ios
compose-mp
compose-ui-showcase
compose-wear
compose-web
connect-audit-events
corda
cork
coroutines
couchbase
coursera
croatia
cryptography
cscenter-course-2016
cucumber-bdd
cyprus
czech
dagger
data2viz
databinding
datascience
dckotlin
debugging
decompose
decouple
denmark
deprecated
detekt
detekt-hint
dev-core
dfw
docs-revamped
dokka
domain-driven-design
doodle
dsl
dublin
dutch
eap
eclipse
ecuador
edinburgh
education
effective-kotlin
effectivekotlin
emacs
embedded-kotlin
estatik
event21-community-content
events
exposed
failgood
fb-internal-demo
feed
firebase
flow
fluid-libraries
forkhandles
forum
fosdem
fp-in-kotlin
framework-elide
freenode
french
fritz2
fuchsia
functional
funktionale
gamedev
ge-kotlin
general-advice
georgia
geospatial
german-lang
getting-started
github-workflows-kt
glance
godot-kotlin
google-io
gradle
graphic
graphkool
graphql
graphql-kotlin
graviton-browser
greece
grpc
gsoc
gui
hackathons
hacktoberfest
hamburg
hamkrest
helios
helsinki
hexagon
hibernate
hikari-cp
hire-me
hiring
hongkong
hoplite
http4k
hungary
hyderabad
image-processing
india
indonesia
inkremental
intellij
intellij-plugins
intellij-tricks
internships
introduce-yourself
io
ios
iran
israel
istanbulcoders
italian
jackson-kotlin
jadx
japanese
jasync-sql
java-to-kotlin-refactoring
javadevelopers
javafx
javalin
javascript
jdbi
jhipster-kotlin
jobsworldwide
jpa
jshdq
juul-libraries
jvm-ir-backend-feedback
jxadapter
k2-early-adopters
kaal
kafka
kakao
kalasim
kapt
karachi
karg
karlsruhe
kash_shell
kaskade
kbuild
kdbc
kgen-doc-tools
kgraphql
kinta
klaxon
klock
kloudformation
kmdc
kmm-español
kmongo
knbt
knote
koalaql
koans
kobalt
kobweb
kodein
kodex
kohesive
koin
koin-dev
komapper
kondor-json
kong
kontent
kontributors
korau
korean
korge
korim
korio
korlibs
korte
kotest
kotest-contributors
kotless
kotlick
kotlin-asia
kotlin-beam
kotlin-by-example
kotlin-csv
kotlin-data-storage
kotlin-foundation
kotlin-fuel
kotlin-in-action
kotlin-inject
kotlin-latam
kotlin-logging
kotlin-multiplatform-contest
kotlin-mumbai
kotlin-native
kotlin-pakistan
kotlin-plugin
kotlin-pune
kotlin-roadmap
kotlin-samples
kotlin-sap
kotlin-serbia
kotlin-spark
kotlin-szeged
kotlin-website
kotlinacademy
kotlinbot
kotlinconf
kotlindl
kotlinforbeginners
kotlingforbeginners
kotlinlondon
kotlinmad
kotlinprogrammers
kotlinsu
kotlintest
kotlintest-devs
kotlintlv
kotlinultimatechallenge
kotlinx-datetime
kotlinx-files
kotlinx-html
kotrix
kotson
kovenant
kprompt
kraph
krawler
kroto-plus
ksp
ktcc
ktfmt
ktlint
ktor
ktp
kubed
kug-leads
kug-torino
kvision
kweb
lambdaworld_cadiz
lanark
language-evolution
language-proposals
latvia
leakcanary
leedskotlinusergroup
lets-have-fun
libgdx
libkgd
library-development
linkeddata
lithuania
london
losangeles
lottie
love
lychee
macedonia
machinelearningbawas
madrid
malaysia
mathematics
meetkotlin
memes
meta
metro-detroit
mexico
miami
micronaut
minnesota
minutest
mirror
mockk
moko
moldova
monsterpuzzle
montreal
moonbean
morocco
motionlayout
mpapt
mu
multiplatform
mumbai
munich
mvikotlin
mvrx
myndocs-oauth2-server
naming
navigation-architecture-component
nepal
new-mexico
new-zealand
newname
nigeria
nodejs
norway
npm-publish
nyc
oceania
ohio-kotlin-users
oldenburg
oolong
opensource
orbit-mvi
osgi
otpisani
package-search
pakistan
panamá
pattern-matching
pbandk
pdx
peru
philippines
phoenix
pinoy
pocketgitclient
polish
popkorn
portugal
practical-functional-programming
proguard
prozis-android-backup
pyhsikal
python
python-contributors
quasar
random
re
react
reaktive
realm
realworldkotlin
reductor
reduks
redux
redux-kotlin
refactoring-to-kotlin
reflect
refreshversions
reports
result
rethink
revolver
rhein-main
rocksdb
romania
room
rpi-pico
rsocket
russian
russian_feed
russian-kotlinasfirst
rx
rxjava
san-diego
science
scotland
scrcast
scrimage
script
scripting
seattle
serialization
server
sg-user-group
singapore
skia-wasm-interop-temp
skrape-it
slovak
snake
sofl-user-group
southafrica
spacemacs
spain
spanish
speaking
spek
spin
splitties
spotify-mobius
spring
spring-security
squarelibraries
stackoverflow
stacks
stayhungrystayfoolish
stdlib
stlouis
strife-discord-lib
strikt
students
stuttgart
sudan
swagger-gradle-codegen
swarm
sweden
swing
swiss-user-group
switzerland
talking-kotlin
tallinn
tampa
teamcity
tegal
tempe
tensorflow
terminal
test
testing
testtestest
texas
tgbotapi
thailand
tornadofx
touchlab-tools
training
tricity-kotlin-user-group
trójmiasto
truth
tunisia
turkey
turkiye
twitter-feed
uae
udacityindia
uk
ukrainian
uniflow
unkonf
uruguay
utah
uuid
vancouver
vankotlin
vertx
videos
vienna
vietnam
vim
vkug
vuejs
web-mpp
webassembly
webrtc
wimix_sentry
wwdc
zircon
Powered by Linen
arrow
  • j

    Joram Visser

    04/02/2021, 6:43 PM
    Just double checking; there is no new
    arrow-fx-coroutines-kotlinx-coroutines
    artifact because there is no more need for suspendCancellable because Arrow Fx Coroutines is now compatible with cancelation from Kotlinx Coroutines?
    r
    • 2
    • 2
  • t

    tDnamein

    04/02/2021, 7:29 PM
    Hi! I do not understand the behaviour of https://arrow-kt.io/docs/apidocs/arrow-core/arrow.core/kotlin.collections.-iterable/compare-to.html (0.13.1). The following applies:
    listOf(1, 0, 0) > listOf(0, 1, 1) == true
    listOf(0, 1, 0) > listOf(1, 0, 1) == false
    Looking at the implementation I understand how this is computed but I believe this is a bug. I am not quite sure, since I do not understand how the compareTo-operator should work on lists but right now the whole outcome is determined by the comparison of the elements at index 0. And If two values at the same position are equal then the whole outcome is determined by the comparison at the next index unless the equality occurred at the end. At least to me it seems like it was not intended to work this way.
    y
    j
    • 3
    • 6
  • d

    ds3fdfd3

    04/03/2021, 8:36 AM
    Hi, does @optics work with internal classes. It seems arrow meta is by default generating public classes. I am trying on 0.13.1.
    s
    • 2
    • 2
  • m

    Mike

    04/04/2021, 12:31 PM
    Should there be a difference in result between
    traversEither
    on a List vs a Nel or am I using it wrong? If I run below Kotest code, The Nel one ends up with 4 elements (the head gets repeated at the end of the list)
    "Test traverseEither on list" {
            val t = listOf(1, 2, 3).traverseEither { i ->
                i.right()
            }
    
            val list = (t as Either.Right<List<String>>).value
            list shouldHaveSize 3 // true [1, 2, 3]
        }
        "Test traversEither on NEL" {
            val fromList = Nel.fromListUnsafe(listOf(1, 2, 3))
            val t = fromList.traverseEither { it.right() }
    
            val list = (t as Either.Right<List<String>>).value
            list shouldHaveSize 3 // false [1, 2, 3, 1]
        }
    a
    y
    • 3
    • 11
  • d

    Daniel Berg

    04/05/2021, 6:20 PM
    Just caught up with the thread of
    traverseEither
    on Nel. The behavior of traverseEither on Iterable was also different than what I expected. It walks the sequence from back to front and also
    f
    is evaluated on all elements even if a Left value is found.
    j
    • 2
    • 6
  • t

    tim

    04/06/2021, 9:56 AM
    Hi all, great work and congrats on 0.13.1! 🥳 I'm just upgrading some of our code, and stumbled on a workaround we had done from last September for Option support in jackson. ... has this been added back in as part of 0.13.1?
    s
    • 2
    • 3
  • b

    Benoît

    04/06/2021, 4:29 PM
    Any update on Kotlin Multiplatform support? It's not in 0.13 right?
    r
    • 2
    • 2
  • m

    Mervyn McCreight

    04/07/2021, 9:23 AM
    Hi 🙂 Are there plans to replace the arrow-fx durations with kotlins duration in arrow (used e.g. in Schedule)? 🙂
    s
    • 2
    • 5
  • d

    Daniel Ryan

    04/07/2021, 9:56 AM
    Hi, I wonder if anyone can help me with a question on how to create a pipeline of transformation functions. Some of the functions return the type that is being operated on directly, and some functions return Either. Below is a contrived example of what I am trying to achieve. The part that I do not like is having to give a name to the intermediate values (i1, i2, etc). If they all returned a simple value (rather than some functions returning either), I could use 'andThen' to compose the functions together. Sorry for the simple question, but I struggle with how to accomplish stuff in a functional way sometimes.
    public suspend fun test(): Unit {
        val add1: (number: Int) -> Int = { it + 1 }
    
        suspend fun divideBy(number: Int, divideBy: Int): Either<Throwable, Int> {
            return Either.catch { number / divideBy }
        }
    
        val result = either<Throwable, Int> {
            val start = 1
            val i1 = add1(start)
            val i2 = !divideBy(i1, 2)
            val i3 = add1(i2)
            add1(i3)
        }
    
        result.fold(
            { println("failed: ${it.message}") },
            { println("result: $it") }
        )
    }
    s
    s
    • 3
    • 6
  • o

    Olivier Laforest

    04/08/2021, 12:39 AM
    Is there an equivalent to comprehension pattern for Reactor’s publisher similar to this
    MonoK.fx {
      //comprehension block
    }.value()
    that we use to be able to do in Arrow 0.11.0 in Arrow 0.13.x?
    s
    • 2
    • 1
  • c

    Chris Paul

    04/08/2021, 12:44 PM
    Semantically speaking, which is more idiomatic?
    Either<Error, Result>
    with an associated
    NotFound
    error type or
    Either<Error, Result?>
    r
    t
    • 3
    • 26
  • a

    Attila Domokos

    04/08/2021, 1:53 PM
    Hello! 👋 I am trying to upgrade our app from 0.11 to 0.13.1, and it seems
    parTupledN
    and
    parMapN
    has been moved and is now deprecated. Is there documentation on how I could resolve this? Thank you!
    s
    • 2
    • 4
  • j

    Josh

    04/08/2021, 4:27 PM
    Hi 👋 , another migration question from
    0.11.0
    to
    0.13.1
    . How would I write this function now:
    suspend fun buildPerson(): Either<DomainError, Person> {
        val name: Either<DomainError, Name> = getName()
        val address: Either<DomainError, Address> = getAddress()
        val dob: Either<DomainError, Date> = getDOB()
        return Either.applicative<DomainError>().tupledN(name, address, dob).map {
            Person(name = it.a, address = it.b, dob = it.c)
        }
    }
    Follow-up: Can I accomplish this in parallel (assuming
    get*
    function are
    suspending
    )?
    r
    s
    • 3
    • 4
  • p

    Pueffl

    04/09/2021, 5:53 AM
    Hi! Can anybody tell me how to refactor this:
    Validated.applicativeNel<Failure>()
            .tupledN(
                    Validated.fromEither(valId).toValidatedNel(),
                    Validated.fromEither(valName).toValidatedNel(),
                    Validated.fromEither(valDescription).toValidatedNel(),
                    Validated.fromEither(valEmail).toValidatedNel(),
                    Validated.fromEither(valFrom).toValidatedNel(),
                    Validated.fromEither(valAuthenticationId).toValidatedNel(),
                    Validated.fromEither(valUrl).toValidatedNel(),
                    Validated.fromEither(valSettings).toValidatedNel(),
                    Validated.fromEither(valProperties).toValidatedNel()
            )
            .fix().toEither()
    s
    • 2
    • 2
  • c

    carbaj0

    04/09/2021, 6:37 AM
    Hi! in the process of migrating to 0.13.1, I have come across a serious refactor,
    interface BankGateway<F> {
        fun bankAccounts(): Kind<F, Result<List<Bank>>>
    }
    the final implementation is ForIO, which means that, do I have to rid of it and use suspend everywhere?
    s
    • 2
    • 3
  • c

    carbaj0

    04/09/2021, 9:33 AM

    https://www.youtube.com/watch?v=CR5h2Wq1yPE&amp;ab_channel=Intersect▾

    This talk was the root of all evils. I was very proud to have built an application abstracting it from the final implementation, now all is suspend hahaha Now I can say that arrow allows you to build the same in a more simple and idiomatic way
    r
    c
    • 3
    • 17
  • m

    Mervyn McCreight

    04/09/2021, 11:05 AM
    Hello :-) What is the new way to do something like:
    val someList = ...
    val someListOfIOs = someList.map { IO { ... } }
    someListOfIOs.sequence(IO.applicativeError())
    Now that IO is gone (and sequence is deprecated)? 🤔 Image I have a list of items, and want to do some side-effect actions for each, but want to short-circuit everything when the first fails.
    s
    s
    • 3
    • 5
  • m

    Mike

    04/09/2021, 11:25 AM
    Look at traverseEither. But be warned there's an issue if the list is an Nel.
    m
    j
    s
    • 4
    • 5
  • h

    Hugo

    04/12/2021, 1:49 AM
    Hey friends, is it reasonable to run suspended functions within an IO? We're migrating from
    IO
    to
    suspend
    and wondering about interoperability. E.g. in this example,
    myFun()
    works as expected, despite
    log(..)
    being a suspended function. I believe this is because
    IO
    now uses
    suspend
    under the hood?
    import <http://arrow.fx.IO|arrow.fx.IO>
    import kotlinx.coroutines.delay
    
    suspend fun log(message: String) {
      delay(1000)
      println(message)
    }
    
    fun myFun(): IO<Unit> = IO {
      log("test")
    }
    
    myFun() // does nothing, suspended
    myFun().unsafeRunSync() // logs "test"
    r
    • 2
    • 3
  • s

    Satyam Agarwal

    04/13/2021, 3:51 PM
    How can I do applicative traverse collecting failures on left hand side ? it was possible in 0.11.0 if I remember correctly, but I can’t seem to write it in the new version. from
    List<A>
    to
    Either<List<B>, List<C>>
    just like we do for validated We only have parTraverse and parTraverseEither. So I can either get
    List<Either<B, C>>
    or
    Either<B, List<C>>
    r
    • 2
    • 7
  • j

    Johan Basson

    04/14/2021, 5:59 AM
    Hi all, could someone provide me with an example on how to use Validated? Thanks.
    r
    s
    • 3
    • 3
  • j

    Jörg Winter

    04/14/2021, 2:12 PM
    Hi, let's say I'd want to use
    either { ... }
    computation in a conventional (non-reactive, controller endpoints are not suspend!) Spring Boot RestController (for validation + effect-short-circuiting) ... what are my options: runBlocking, or some other recommended 'bridge to suspend-world' ? Obviously this concern could become obsolete if mainstream actually moves away from 'blocking Spring', but what recommendations (if any specific exist) are there until then ?
    s
    • 2
    • 6
  • s

    simon.vergauwen

    04/14/2021, 5:15 PM
    Shameless plug... In case someone missed it 😄 https://www.47deg.com/blog/functional-domain-modeling-part-2/
    👏 20
    t
    • 2
    • 4
  • j

    Jimmy Alvarez

    04/14/2021, 8:30 PM
    Hey guys, hope you doing good! Currently i`m working on code coverage of some functions using cooroutines, my problem is that i dont know how to cover those lines that launch coroutines like:
    runBloking {}
    s
    • 2
    • 7
  • j

    Jimmy Alvarez

    04/15/2021, 1:47 AM
    Another question that may you guys could help me. I’m working on a functionality that fetch a list of users and validate each to know if it need to be deleted or not. I have 2 methods. first one is to fetch users
    fun getUsers(max: Int): Either<LowUnprotectedError, List<User>>
    and the other one is the validate method
    fun isCandidateToDelete(user: User): Either<LowUnprotectedError, Boolean>
    . Then i need to star the process for each user, but given the method to validate the user is in a Either, I need to fold it in order to know the result of verification like this :
    val usersDelete = users.filter { repository.isCandidateToDelete(it).fold({ false }, { it }) }`
    Could you imagine a better way to accomplish this process. Please let me know if i was not clear with this question, thanks in advance!!
    s
    • 2
    • 13
  • c

    Cody Mikol

    04/15/2021, 3:21 PM
    What is the correct way to transform an
    Iterable<Either<L,R>>
    into a
    Validated<Nel<L>, R>
    ? For more context, I’m using parTraverse on a collection, returning an
    Either<L,R>
    for each item. I’d like to collect that into a
    Validated<Nel<L>,R
    to that I can take the left path if there are any errors and collect that into some useful log message. It looks something like
    items
      .parTraverse { doWork(it, foo) }
      .toValidated() // This is what I'm trying to figure out.
      .mapLeft { makeErrorMessage(it) // where it is Nel<L> }
    
    fun doWork() : Either<L,R>
    ➕ 1
    a
    s
    • 3
    • 3
  • b

    Brad M

    04/15/2021, 6:41 PM
    I see there is a
    traverseEither
    for
    Map
    , is there a
    parTraverseEither
    ? This is what I have right now:
    val items = // Map<K,V>
    val newUrls = items.entries
      .parTraverseEither { (key, value) -> doWork(key, value).map { Pair(key, it) } }
      .map { it.associate { (first, second) -> first to second } }.bind()
    s
    • 2
    • 2
  • i

    Ifvwm

    04/16/2021, 5:50 AM
    class DownloadStructure(val name: String, val link: String, val size: Int) { fun fmap (f: (String) -> String): DownloadStructure = DownloadStructure(name, f(link), size) } // why this would cause class Redeclaration error?
    s
    • 2
    • 1
  • c

    Cody Mikol

    04/16/2021, 1:10 PM
    What is the current suggestion to replace tupled ?
    p
    s
    +3
    • 6
    • 13
  • i

    ivanmorgillo

    04/18/2021, 8:33 AM
    Hi all, this might be a stupid question and even stupider to do on a Sunday morning 😂 but I was wondering if we should expect changes or deprecation on
    Either
    when
    Result<T>
    will be easily available in Kotlin 1.5 (https://github.com/Kotlin/KEEP/pull/244) I'm planning some lessons for my students about
    Either
    and I'm afraid they will question the benefits once they will be able to use
    Result
    . I'm not sure that
    Result
    will have
    flatMap
    & Co. tho 🤔 Any insight? 😄
    r
    s
    s
    • 4
    • 33
Powered by Linen
Title
i

ivanmorgillo

04/18/2021, 8:33 AM
Hi all, this might be a stupid question and even stupider to do on a Sunday morning 😂 but I was wondering if we should expect changes or deprecation on
Either
when
Result<T>
will be easily available in Kotlin 1.5 (https://github.com/Kotlin/KEEP/pull/244) I'm planning some lessons for my students about
Either
and I'm afraid they will question the benefits once they will be able to use
Result
. I'm not sure that
Result
will have
flatMap
& Co. tho 🤔 Any insight? 😄
r

raulraja

04/18/2021, 9:15 AM
Happy sunday @ivanmorgillo, Either won’t be impacted by changes to Result because
Either
is generic in its error and left side while
Result
has it’s left fixed to
Throwable
. What will happen in Arrow core is that once these restrictions are lifted and
Result
becomes generically available you will see the APIs of
Either
also available over
Result
including support for
Result
in either comprehensions and other places where its compatible. Ultimately Either is
Either<E, A>
but Result is only
Result<A>
where there is an implicit left Throwable embedded.
👍 1
Either would disappear from Arrow as a data type if the std lib embedded a equivalent version of it but so far it doesn’t. If it did we would happily accomplish our mission and remove from Arrow, in the same way you don’t find Either in other FP libraries like cats but instead just extended support for it.
👌 2
i

ivanmorgillo

04/18/2021, 9:18 AM
so if I get it correctly, Arrow is gonna provide
flatMap
on
Result
?
r

raulraja

04/18/2021, 9:19 AM
It will for consistency with Either and also
result.bind()
inside the
either
and
result
computation expressions.
👍 1
It would provide flatMap if Result doesn’t already provide it
same as we do for the
Iterable
support + comprehensions or similar. If you or anyone want to give it a shot at porting the support we’d be happy to help with any questions and review. At some point when it’s stable will be added as we had discussed this before in our planning meetings.
i

ivanmorgillo

04/18/2021, 9:39 AM
sounds great, thanks 👍 about the porting part, I feel it's a bit beyond my possibilities, but I'm always up for testing and feedback 😊
👍 2
s

stojan

04/18/2021, 9:47 AM
Result can't replace Either, as the left side is hard-coded to Throwable (with Either you can have any type as the left side... And it's not limited to error handling) https://kotlinlang.slack.com/archives/C5UPMM0A0/p1616323430016900?thread_ts=1616323430.016900&amp;cid=C5UPMM0A0
i

ivanmorgillo

04/18/2021, 9:57 AM
I see the point, but even with
Either
most of the time we, me and my students, only use it with
Throwable
. Sometime we have a
sealed class
on the left, but then we hit the infamous:
Oh now we have 15 different
NoInternet
types, one for every possible network call that can fail 😞
At this point I should talk about Union Types. Coproduct... and we move from
This network call can fail with an error.
to
WTF is this thing!? Can't we use try/catch and return
null
?!
✅ 1
I'm constantly trying to onboard people on Arrow. Often is not easy to present a case that makes sense to them.
r

raulraja

04/18/2021, 9:59 AM
The network can fail with an error is already covered by
suspend () -> A
since the continuation exits always in Result<Throwable, A> and as long as you are in suspend you’ll be forced to handle at some point or blow up in suspend main
Perhaps those error case adts are too granular
i

ivanmorgillo

04/18/2021, 10:00 AM
on Android is common to have different error messages or behaviors in case of errors:
sealed class {
  NoInternet
  UserNotFound
  Timeout
}
r

raulraja

04/18/2021, 10:00 AM
Most times you should not worry about Either with throwable and error adts ususally don’t need exceptions at all. At most you can have a case
GenericError(Throwable)
in the ADT
yes none of those need exceptions
they could be constructed with the type of Throwable where you detect those cases but the values themselves don’t need to extend Throwable
i

ivanmorgillo

04/18/2021, 10:02 AM
the fact is that if I have 3 screens and all 3 of them have a network call, I will end up with 3 sealed classes that contains
NoInternet
and
Timeout
over and over
r

raulraja

04/18/2021, 10:03 AM
You can compose ADTs in a way those errors live in a common place
i

ivanmorgillo

04/18/2021, 10:04 AM
at the same time, I don't want to use
Throwable
because I don't want my ViewModel to know that
IOException
is probably the user not having internet connection
to mix and match errors, I user Coproduct in the past
r

raulraja

04/18/2021, 10:05 AM
sealed class Error 
object  NoInternet : Error()
object  UserNotFound: Error()
object  Timeout: Error()

sealed class UiError
data class ServiceError(val error: Error) : UiError()
object ScreenOff : UiError()
i

ivanmorgillo

04/18/2021, 10:05 AM
suspend fun loadUser(id): Either<Coproduct<NoInternet, TimeOut, NoUser>>, User>
r

raulraja

04/18/2021, 10:05 AM
There
Error
may be in a different module
Coproduct will come back as union types ~ 1.7
It’s already implemented but can’t be supported in IDEA until then.
i

ivanmorgillo

04/18/2021, 10:07 AM
with your example, if I use
Error
in a screen that doesn't need
UserNotFound
, when I do
when(error)
I get also a case that I don't need, right?
r

raulraja

04/18/2021, 10:10 AM
yes, but in that screen you would not match on error but instead have maybe an `Either<UiError, *> where you map left or fold and ignore
ServiceError
or you cuold also have the Either<TypeICare, *> in that screen only. This is how decision in typing forces you to go from an error type to another across layers.
we assumed you cared about UserNotFound generically but if its not the case maybe that goes in auth only layer
In that screen you’d be matching on UiError. Normally you may define errors in different layers based on concerns of those layers and then a top common definition of errors that can happen anywhere or can be reused across modules
i

ivanmorgillo

04/18/2021, 10:38 AM
imagine I have repository with these functions:
suspend fun loadUser(id) : Either<XYZ, User>
suspend fun loadFriends(id) : Either<ABC, Nel<Friend>>
Both can fail with
NoInternet
SlowInternet
On top of that, the first one can fail also with
UserNotFound
, while the second one can fail with
NoFriendsFound
. How could I model it to be sure that
UserProfileViewModel
is able to work with
NoInternet
SlowInternet
UserNotFound
and
FriendsListViewModel
can work with
kotlin
NoInternet
SlowInternet
NoFriendsFound
This is my pain point right now.
slack markdown is drunk
s

stojan

04/18/2021, 11:38 AM
my 2 cents
// suspend fun loadUser(id) : Either<XYZ, User>
sealed class UserError {
    object Timeout : UserError()
    object NoInternet : UserError()
    object UserNotFound : UserError()
}

//suspend fun loadFriends(id) : Either<ABC, Nel<Friend>>
sealed class FriendsError {
    object Timeout : FriendsError()
    object NoInternet : FriendsError()
    object NoFriendsFound : FriendsError()
}

// We can extract duplicaton
sealed class NetworkError<A> {
    object Timeout : NetworkError<Nothing>()
    object NoInternet : NetworkError<Nothing>()
    data class ApiError<A>(val a: A) : NetworkError<A>()
}

// Now we can use composition
object UserNotFound
typealias UserError2 = NetworkError<UserNotFound>
object NoFriendsFound
typealias FriendsError2 = NetworkError<NoFriendsFound>
    
    
// However, are we handling Timeout and NoInternet differently?
// Probably not, at most we have a different error message + retry button
// Usually we have a generic: We couldn't connect, check your network and try again

// Do we really handle UserNotFound and NoFriendsFound differently?
// From domain perspective we asked for a resource and it's not there
// We can actually handle the different error message in the VM
// In this scenario a retry would probably not help, the resource won't magically appear

sealed class ApiError {
    object InternetError : ApiError() // Timeout + NoInternet
    object NotFound : ApiError() // UserNotFound + FriendsNotFound
}
➕ 4
👌 1
s

simon.vergauwen

04/19/2021, 7:13 AM
sealed interface
in Kotlin 1.5 and later will also really help. Then you can mix in multiple
sealed interfaces
into a singe ADT.
➕ 2
View count: 2