https://kotlinlang.org logo
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
  • i

    Ifvwm

    04/18/2021, 12:01 PM
    is IO <A> depreciated?
    i
    r
    k
    • 4
    • 9
  • d

    Daniel Berg

    04/20/2021, 3:00 AM
    Hi guys, I think we ran into a problem reported here: https://github.com/arrow-kt/arrow/issues/2375
    s
    • 2
    • 16
  • i

    Ifvwm

    04/20/2021, 8:21 AM
    what's the usage of
    either { ... } ?
    I can't find documents about it, related to
    Either.fx<A,B> { ... } ?
    s
    • 2
    • 10
  • d

    drew

    04/20/2021, 8:55 PM
    i’m trying to understand how to design the following with validated — i have a nullable field. if it is
    null
    , i want to return an error. if not, i want to run several validations against the non-null data. how would i go about this?
    .withEither
    doesn’t seem correct, because i want to operate with
    Validated
    , not
    Either
    .
    r
    • 2
    • 27
  • r

    rpillay

    04/21/2021, 6:06 AM
    Looks like its an open issue to update this: https://github.com/arrow-kt/arrow-integrations/issues/44
    r
    m
    r
    • 4
    • 32
  • d

    drew

    04/21/2021, 2:42 PM
    fun <E, A, B> Validated<E, A>.andThen(next: (A) -> Validated<E, B>): Validated<E, B> =
        this.withEither { first ->
            first.flatMap { next(it).toEither() }
        }
    j
    r
    • 3
    • 8
  • h

    Hexa

    04/21/2021, 4:04 PM
    my build.gradle.kts file has these dependencies
    dependencies {
        implementation("io.arrow-kt:arrow-core:0.13.1")
        implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
    }
    m
    • 2
    • 1
  • h

    Hexa

    04/21/2021, 4:06 PM
    does kotlin arrow support Java 11?
    j
    s
    +3
    • 6
    • 13
  • c

    carbaj0

    04/27/2021, 11:50 AM
    listEithers.map { it.toDomain() }.traverse(Either.applicative(), ::identity).map { it.fix().toList() }
    vs
    listEithers.map { it.toDomain() }.traverseEither { it }
    s
    • 2
    • 6
  • c

    Cody Mikol

    04/27/2021, 5:47 PM
    Is there a better way to do something like this?
    listOf(
    { foo() }
    { bar() }
    { baz() }
    ).parTraverseEither { it() }
    c
    c
    • 3
    • 4
  • c

    Cody Mikol

    04/28/2021, 12:21 AM
    What is the benefit to having methods like parTraverseEither / parSequenceEither be suspended functions since they are internally doing the work in parallel and then returning some result? Would wrapping the internals of that call in a
    runBlocking
    lambda have a negative impact on its behavior? Given the scenario that I want a method capable of taking in a list of strings and then resolving something via HTTP I seem to have a two options. 1. Make the method suspended, this requires callers to be suspended as well
    suspend fun parRequireStrings(resolvers: List<String>): ValidatedNel<Error, List<String>> = properties
            .parTraverseValidated(Semigroup.nonEmptyList()) { requireString(it).toValidatedNel() }
    2 Make the method block so the callers don’t have to be suspended
    fun parRequireStrings(resolvers: List<String>): ValidatedNel<Error, List<String>> = runBlocking { 
      properties.parTraverseValidated(Semigroup.nonEmptyList()) { requireString(it).toValidatedNel() }
    }
    The second option seems more desirable as you can call it outside of suspended functions, are there any drawbacks to this approach?
    s
    • 2
    • 4
  • c

    Cody Mikol

    04/29/2021, 11:59 PM
    If
    parTraverseEither
    will short circuit and take the left path on the first error, is there some way to collect errors in parallel into a
    Validated<Nel<L>,R>
    c
    • 2
    • 3
  • b

    Brad M

    04/30/2021, 8:43 PM
    hey y’all, is there a nice way to handle a nullable type that also has an
    isEmpty
    method that is functionally equivalent in our case to null? For example:
    val files: Map<UUID, MultipartFile>;
    
    val fileUrls = if (files?.isNotEmpty()) {
      uploadFiles(files).bind() // returns Either<MyError, Map<UUID, Url>>
    } else null
    c
    • 2
    • 4
  • s

    Satyam Agarwal

    05/01/2021, 2:45 PM
    Does arrow-kt have a fire and forget concept ? I want to offload my computation (can be heavy IO ops) in the background. I have aware of
    CoroutineScope.actor
    . But was wondering if I can get something functional.
    j
    s
    • 3
    • 21
  • c

    Cody Mikol

    05/06/2021, 7:12 PM
    I’m noticing
    Runtime exception  Handler dispatch failed; nested exception is java.lang.NoSuchMethodError: 'java.lang.Object arrow.core.Either$Right.getB()'
    r
    • 2
    • 3
  • j

    Jimmy Alvarez

    05/11/2021, 2:47 AM
    DOes it make sense to use Arrow FX and Flow from coroutines?
    s
    • 2
    • 3
  • d

    dephinera

    05/12/2021, 12:01 PM
    Where is the
    arrow.core.extensions.either.apply.mapN
    function moved to? I expected it to be in
    Either.mapN
    , however by using arrow-core 0.13.2, I can't find such reference. I couldn't find the release notes where that changed either
    r
    s
    • 3
    • 4
  • j

    Jeff

    05/12/2021, 6:58 PM
    Is there a more idiomatic way to nest Eithers? This is what I have.
    sourceA().handleErrorWith {
        sourceB().handleErrorWith {
            sourceC()
        }
    }
    j
    s
    • 3
    • 17
  • g

    Gopal S Akshintala

    05/14/2021, 10:40 AM
    Hi, would like to know the rationale behind having some functions like
    filterOrElse
    as Extensions to
    Either
    instead of member functions? This won’t let to be used as a dot function when consumed from Java. I know Arrow is not designed for Java consumption, but is there any advantage of having this as extension over member? If not can these functions be made member fns, so we get an added advantage of consuming them from Java
    r
    • 2
    • 9
  • c

    Cody Mikol

    05/14/2021, 3:36 PM
    Is there an equivalent to
    also
    in arrow for things like logging? Currently doing something like
    foo()
    .mapLeft { it.also { logger.error("Something terrible has happened!") } }
    .map { it.also { logger.success("Something good has happened!") } }
    m
    • 2
    • 14
  • t

    thanh

    05/15/2021, 8:09 AM
    Hi is there any way I can try refined-types plugins today (without setup Arrow-Meta locally)?
    r
    • 2
    • 2
  • c

    carbaj0

    05/15/2021, 11:44 AM
    although I have post it in the general, I trust your wisdom 😀
    h
    c
    • 3
    • 13
  • b

    Benoît

    05/18/2021, 8:39 AM
    Hi everyone, any update on Arrow's compatibility with Kotlin Multiplatform?
    r
    • 2
    • 3
  • d

    dnowak

    05/18/2021, 10:52 AM
    Hi, what is the replacement for:
    IO {
      //something may throw exception here
    }.handleError { t -> 
      //map exception to some result
    }
    p
    • 2
    • 8
  • r

    rpillay

    05/20/2021, 4:09 AM
    Hi all I noticed that I'm not able to call co-routine methods within a flatMapped arrow Either. eg. Something like
    someEither.flatMap { someCoroutineMethod() <- // this causes an error - "Suspension functions can be called only within coroutine body" }
    If we were to make flatMap an inline function (ie.
    inline fun <A, B, C> EitherOf<A, B>.flatMap(f: (B) -> Either<A, C>): Either<A, C> = ...
    That would allow it to be called. This is similar to the .fold we have on Either. Is there a reason we shouldn't make this change?
    c
    • 2
    • 4
  • p

    Peter

    05/20/2021, 9:58 PM
    does anyone know if it’s possible to check if a partial function is defined for a certain value in kotlin? like scala’s
    f.isDefinedAt
    s
    • 2
    • 2
  • j

    Jeff

    05/21/2021, 6:00 PM
    I have an Either<A, B>. I want to call .map to make it an <A, C> but the map may produce an A. Is there a way to do this with map or is there something else? ex;
    myEither.map { 
      try { 
        it.toC() 
      } catch (e: Exception) { 
        A() 
      } 
    }
    p
    • 2
    • 2
  • j

    Jeff

    05/21/2021, 6:40 PM
    I have a question about Fx. The docs talk about using
    suspend
    to signal side-effecty functions. When I do this my IDE gives me helpful hints saying I don’t need the
    suspend
    keyword since I don’t call any suspend functions. Is there a typical solution for this? Do I just suppress / annotate it away?
    r
    s
    • 3
    • 4
  • e

    EarthCitizen

    05/25/2021, 6:37 PM
    Which dependency contains the
    arrow.core.extensions
    package? I am trying to do
    Either.applicative()
    , in case I am wrong about where to find this
    s
    r
    • 3
    • 7
  • t

    Tower Guidev2

    05/27/2021, 5:13 PM
    Hi, I require Higher Kinded types in my current project. I believe Arrow has deprecated them though, therefore what approach has replaced Arrows Higher Kinded Types?
    j
    r
    +2
    • 5
    • 32
Powered by Linen
Title
t

Tower Guidev2

05/27/2021, 5:13 PM
Hi, I require Higher Kinded types in my current project. I believe Arrow has deprecated them though, therefore what approach has replaced Arrows Higher Kinded Types?
j

Jannis

05/27/2021, 5:34 PM
Strictly speaking: Nothing. Higher kinds are simply not very usable in kotlin and have been quite the pain point for a while. Now that is not the whole story: Higher kinds are usually used for effects, and those can be emulated sufficiently via suspend functions and concrete types. For example most normal application use can get by with using
IO = suspend
and
Either
for modeling errors. To be clear, this is simply not equally powerful as higher kinded types in kotlin and there is a lot this cannot do, however it is easier to use and sufficient for most. There are two common uses for higher kinds: • monad stacks for effects: This is replaced by
suspend
functions and comprehensions, however atm it is not equally powerful because kotlin continuations cannot be resumed multiple times and thus we can only model short-circuit-like monads with effects (such as
either
or any nullable type).
IO
is equal to
suspend
in arrow terms. • Abstracting over "containers" of values. This is simply not possible without kinds, suspend functions or not. If your use case falls under this category, you are better off rolling your own kind implementation 😕 But with arrow-meta this may very well come back at some point, but for now its simply not there...
So in short: Arrow has moved away from kinds and typeclasses, to exporting more function over suspend and the base types such as
Either
. Kinds may or may not come back, but not in the form as before and certainly not without compiler plugins
r

raulraja

05/27/2021, 5:38 PM
I was writing a long response but @Jannis’s is better 🙂. I would just add that suspend is more powerful than IO in the sense that it can also avoid transformer stacks by using inline functions. This is more ergonomic and more Kotlin like that something based on
F
or transformer stacks for the case of IO which is what F is most of the time. It’s also much faster because the compiler optimizes suspend programs over your traditional IO based ones. Even with kinds, since in Kotlin they are emulated, partially applying type arguments of kinds like Either and downcasting with
fix
is painful and something we don’t want to proliferate as idiom in Arrow.
t

Tower Guidev2

05/28/2021, 8:28 AM
thanks for your time in responding, maybe I have the wrong solution for my requirement. What I am attempting to achieve is to to define a relationship between two types. as an example imagine an
Input
and
Output
, what I require is to define that
Input1
can only produce
Output1
, and
Input2
can only produce
Output2
etc.. in addition I also need to define the data type contained in each
Input
and
Output
, so that
Input1
can only contain a
String
, and
Output1
can only contain a
Long
(I am only using these simple data types for example purposes, in reality I would use Complex custom
data classes
) , wouldnt Higher Kinded Types solve this for me?, I am lost as to develop another solution that can both define a strict releationship between my Input & Output types and the data they contain. I need to be able to define that Input1 can only ever contain DataTypeA and only ever produce Output1; That Output1 can only ever contain DataTypeB. I wish to define an entire "family" of Input(s) and Output(s) that have the above restrictions. Is that possible in Kotlin?
s

streetsofboston

05/28/2021, 11:32 AM
Are you thinking as about type proofs?

https://youtu.be/lK80dPcsNUg▾

r

raulraja

05/28/2021, 12:43 PM
Type proofs can constraint that but is not ready for use and it’s being split into smaller focused plugins for given, macros and refined types.
@Tower Guidev2 Do you have a small example with kinds or without of what it looks like with code?
What you describe there sounds more like a type refinement than a kind itself. Maybe value classes and refined types can help https://meta.arrow-kt.io/apidocs/arrow-refined-types/arrow.refinement/
t

Tower Guidev2

05/28/2021, 1:39 PM
Im an Android developer trying to get to grips with MVI Im attempting to define User Actions such as LoginAction. Each Action will have an associated Reaction, e.g. LoginReaction. I want to restrict that LoginAction can only ever produce a LoginReaction And more generally Action1 can only ever produce Reaction1, Action2 can only ever produce Reaction2 In pseudo code
val action: Action = LoginAction(username, password)
viewmodel.react(action).collect {
reaction ->
when (reaction) {
LoginReaction -> println("\t\t ${reaction.reaction.output}")
Reaction1 -> println("\t\t ${reaction.reaction.output}")
Reaction2 -> println("\t\t ${reaction.reaction.output}")
Reaction3 -> println("\t\t ${reaction.reaction.output}")
}
}
In my viewmodel the react function I would have
fun react(action: Action): Flow<Reaction> = flow {
val reaction: Reaction = when (action) {
is LoginAction -> {
Val accessCode = callLoginApi(it.password, it.username)
LoginReaction(accessCode)
}
is ActionOne -> {
Reaction1(42L)
}
is ActionTwo -> {
Reaction2(CustomOutput(frank = 24L, homer = "Help!"))
}
is ActionThree -> {
Reaction3(CustomOutputTwo(geezer = 2442L, su = "Why"))
}
else -> TODO()
}
emit(reaction)
}
r

raulraja

05/28/2021, 5:30 PM
@Tower Guidev2 This is how I would model what I understood you are trying to achieve to ensure a given Reaction belongs to a specific type of Action https://gist.github.com/raulraja/5ebbd75061343b78260148719e3dcd05
🤩 1
t

Tower Guidev2

06/01/2021, 9:30 AM
@raulraja thanks very much for taking the time to develop this solution. It is indeed elegant 😄 However I am having difficulty in refactoring your solution to fit my requirement (as I am a Kotlin newbee) the issue I am having is I cannot get past this compile error
Type mismatch: inferred type is LoginReaction but Reaction<{A & LoginAction}> was expected
, when splitting your solution to fit how I wish to design my Android App. My issue is that each Android Activity will create multiple Action(s) and collect the related Reaction(s) I've attempted to refactor your code as follows:- In My Android ViewModel class I have created these two functions
fun <A : Action> react(action: A): Flow<*> = flow {
    
    val reaction = when (action) {
        is LoginAction -> {
            val accessToken : String = LoginApi.login(action.password, action.password) // This is an Asynchronous RESTful API call
            react(action) { LoginReaction(accessToken) }  // COMPILE ERROR HERE!!!!!!!!!!!!
        }

        else -> TODO()
    }


    emit(reaction)

}

/**
 * This is the motherload. This function ensures that a given [Action] [A]
 * creates a [Flow] of [Reaction] for [R], a Reaction that only accepts actions of type [A]
 */
private inline fun <X : Action, Y : Reaction<X>> react(action: X, crossinline function: (X) -> Y): Reaction<X> {
    return function(action)
}
I call my public react fucntion from my activity:-
val loginAction = LoginAction(UserName("test"), Password("test"))
viewmodel.react(loginAction).collectLatest {
    println("debug $it")
}
where has my lack of Kotlin expertise let me down? 🤔
r

raulraja

06/01/2021, 10:04 AM
Hi @Tower Guidev2, I think it may be some issue with the definition of the Action and Reaction hierarchies. Do you have this code somewhere public I can try to compile that shows the issue? Ideally without the Android deps 🙂
t

Tower Guidev2

06/01/2021, 10:20 AM
Does this make sense @raulraja https://gist.github.com/tower-guidev2/013c777ffedd98545f6bcb2aac7bfba1 😄
r

raulraja

06/01/2021, 10:51 AM
That makes sense but you are hitting a known limitation of Kotlin. Kotlin does not unify generics over all the values of a sealed hierarchy, it only uses sealed hierarchies for exhaustive pattern matching. Let me try to attempt to reencode the problem in a way where types would be fine. It involves making actions aware of which reactions they support in their flows.
t

Tower Guidev2

06/01/2021, 10:57 AM
Thanks for the explanation.. 😄
r

raulraja

06/01/2021, 11:09 AM
I guess in your example if you just want to work around the type limitation because your handler receives a generic action value and you just have to pattern match you could encode it like this:
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow

class Aardvark {

  inline suspend fun <A : Action> react(action: A): Flow<Reaction<*>> =
    when (action) {
      is LoginAction -> react(action) { LoginReaction("UUID.randomUUID().toString()") }
      is ActionOne -> react(action) { ReactionOne("UUID.randomUUID().toString()") }
      else -> TODO()
    }

  inline suspend fun <X : Action, Y : Reaction<X>> react(action: X, crossinline function: (X) -> Y): Flow<Y> =
    flow { emit(function(action)) }
  
}
Embed the Flow in the reaction so it embeds the type
Y
of Reaction in its type argument and inference then knows
Y
above has to unify as a
Reaction<*>
. Since
Y
is declared as
Reaction<X>
and
*
in kotlin means
DONT_CARE
then it unifies properly. If you try to decompose in cases you will have to manually cast like in your case if you want to make it compile because Kotlin does not make an effort to unify generic type bounds with sealed hierarchies.
Also you don’t need in this case
A : Action
should work with just
Action
no type args since A is not reified or used in a projection in the return type
BTW this is my favorite sauce, should try it if you can ever get your hands on it https://secretaardvark.com/ xD
😆 1
t

Tower Guidev2

06/01/2021, 12:20 PM
@raulraja Thanks for resolving my issue and the hot sauce recommendation 😄 I hope I havent wasted too much of your time 😄
r

raulraja

06/01/2021, 12:23 PM
no problem! glad I could help 🙂
j

julian

06/01/2021, 3:01 PM
@raulraja I'm having trouble understanding this, can you unpack it a bit?
Kotlin does not make an effort to unify generic type bounds with sealed hierarchies
Also, while the use of generics and inline is of great interest to me, it's unclear to me what has been gained over the original implementation i.e.
fun react(action: Action): Flow<Reaction> = flow {
    val reaction: Reaction = when (action) {
        is LoginAction -> {
            Val accessCode = callLoginApi(it.password, it.username)
            LoginReaction(accessCode)
        }
        is ActionOne -> {
            Reaction1(42L)
        }
        is ActionTwo -> {
            Reaction2(CustomOutput(frank = 24L, homer = "Help!"))
        }
        is ActionThree -> {
            Reaction3(CustomOutputTwo(geezer = 2442L, su = "Why"))
        }
        else -> TODO()
    }
    emit(reaction)
}
since the consumer of the flow is going to have to
when-is
on the
Reaction
s in the flow, either way.
r

raulraja

06/01/2021, 4:53 PM
Hi @julian , what I ment in the first case is that Kolin can’t make Generic ADTs unify to a type parameter A even if you contemplate all cases of the match, here is an unrelated example of the same problem and without type associations between the ADTs beside the generic type argument.
sealed interface Exp<A>
data class NumberExp(val value: Int): Exp<Int>
data class StringExp(val value: String): Exp<String>

sealed interface Codec<A>
object IntCodec: Codec<Int>
object StringCodec: Codec<String>

fun <A> cantUnifyA(expr: Exp<A>): Codec<A> =
  when (expr) {
    is NumberExp -> IntCodec //Type mismatch: inferred type is IntCodec but Codec<A> was expected
    is StringExp -> StringCodec //Type mismatch: inferred type is StringCodec but Codec<A> was expected
  }
there is no gain unless the user uses directly the typed
react(action) { reaction }
to create its flows all individually
A way to work around the issue unifying the type arg A on two separate ADTs is to define abstract members in Action to react and making the subclasses implement them.
This would require no unification as you would just call
action.react()
which on the base class would have returned
Reaction<A>
where A is always matched by the members instead of using pattern matching.
With this new version the example above can indeed unify A:
sealed interface Exp<A> {
  fun codec(): Codec<A>
}
data class NumberExp(val value: Int): Exp<Int> {
  override fun codec(): Codec<Int> = IntCodec
}
data class StringExp(val value: String): Exp<String> {
  override fun codec(): Codec<String> = StringCodec
}

sealed interface Codec<A>
object IntCodec: Codec<Int>
object StringCodec: Codec<String>

fun <A> canUnifyA(expr: Exp<A>): Codec<A> =
  expr.codec()
But this encoding forces you to handle the cases in the classes
here it knows
Codec<A>
refers to the same
A
as
Expr<A>
j

julian

06/01/2021, 5:28 PM
Okay, I get it now. Thanks so much for explaining in such detail.
r

raulraja

06/01/2021, 5:28 PM
The general issue is that kotlin does not know how to unify type arguments in when exhaustive matches for ADTs that are GADTs meaning they have type arguments
:thank-you: 1
View count: 50