Is there a reason compose, andThen etc don't suppo...
# arrow
p
Is there a reason compose, andThen etc don't support composing suspend functions?
s
You can just call them in order, imperatively and sequentially.
p
the same can be said about ordinary functions as well.
r
the main reason is because
(A) -> B
is not the same type as
suspend (A) -> B
since the latter becomes
(A, Continuation<B>) -> Unit
s
Ah…. sorry… for some reason, I thought your msg was in the #coroutines channel… I guess the Arrow folks haven’t written the
andThen
functions (and others) for
suspend
funs. You could write your own 🙂
r
Which means that support the n-arity of composition for function22 we would need suspend function 22 too, if you can find a different way, this is a known limitation
p
For just the infix notations, if I define something like this, do you see any potential downsides?
Copy code
fun <X, Y, Z> compose(f: (X) -> Y, g: (Y) -> Z): (X) -> Z = { x -> g(f(x)) }
suspend fun <X, Y, Z> compose(f: suspend (X) -> Y, g: suspend (Y) -> Z): suspend (X) -> Z =  { x -> g(f(x)) }
suspend fun <X, Y, Z> compose(f: (X) -> Y, g: suspend (Y) -> Z): suspend (X) -> Z =  { x -> g(f(x)) }
suspend fun <X, Y, Z> compose(f: suspend (X) -> Y, g: (Y) -> Z): suspend (X) -> Z =  { x -> g(f(x)) }

// Syntax sugar for `g after f` notation.
infix fun <X, Y, Z> ((Y) -> Z).after(f: (X) -> Y): (X) -> Z = compose(f, this)
suspend infix fun <X, Y, Z> (suspend (Y) -> Z).after(f: suspend (X) -> Y): suspend (X) -> Z = compose(f, this)
suspend infix fun <X, Y, Z> ((Y) -> Z).after(f: suspend (X) -> Y): suspend (X) -> Z = compose(f, this)
suspend infix fun <X, Y, Z> (suspend (Y) -> Z).after(f:(X) -> Y): suspend (X) -> Z = compose(f, this)

// Syntax sugar for f andThen g notation.
infix fun <X, Y, Z> ((X) -> Y).andThen(g: (Y) -> Z): (X) -> Z = compose(this, g)
suspend infix fun <X, Y, Z> (suspend (X) -> Y).andThen(g: suspend (Y) -> Z): suspend (X) -> Z = compose(this, g)
suspend infix fun <X, Y, Z> ((X) -> Y).andThen(g: suspend (Y) -> Z): suspend (X) -> Z = compose(this, g)
suspend infix fun <X, Y, Z> (suspend (X) -> Y).andThen(g:(Y) -> Z): suspend (X) -> Z = compose(this, g)
r
yep, thanks @streetsofboston, also I think this composition can be solved with a compiler plugin that does the composition synthetically at the call site so it does not require the 22 arities that is why we did not commit to 22 new suspend functions for each compose, andThen, partially etc
s
@raulraja IIRC, with kotlin 1.4, you can assign a regular lambda to a val/var that is declared to be a suspend fun. Would that help with redefining the
andThen
and others to make the available for both suspend and regular functions?
r
maybe, there is also interface fun which auto matches by structural shape
p
it actually requires 3 variants for composing 2 functions
Atleast the infix variants are simpler, we don't need to implement this for all 22 variants (which would be monstrous)
r
oh you want to interleave suspend and non suspend composition @Phani Mahesh?
p
No reason to forbid that, right? I have a pure computation and a suspend function, I want to be able to compose them freely as well.
r
as long as they result in suspend always no reason but if that is the case you can just make it all inline
p
like
::getUserFromDb andThen ::getDisplayName
r
then they’ll be copure passing through suspension regardless
p
oh inlining lets me cut it down? let me check that,
r
an inline function in Kotlin is more than an optimization, it less effects in suspend pass through as it gets desugared with the suspension CPS loop so it should be able to let us define those as inline and it will take in any suspend and non suspend function as args
maybe asks you to cross inline in this case, haven’t checked.
p
no, marking them inline still requires me to write all combinations of suspend, even with crossinline
s
inline
doens't work here since in the end you're wrapping in a regular lambda which is where the inlining stops. So you still need to duplicate the non-suspending and suspending syntax, so you can wrap in a regular -and a suspend lambda.
👍 1