Satyam Agarwal
09/14/2020, 8:45 AMparTupleN is why this method exists again ? In IO, parMapN was deprecated in favor of parTupledN because the returned type was not aligned with returned type of other apis in the library.
If I use parTupleN from arrow-fx-coroutines, I was expecting that if I am giving it 2 methods with Either return types, it should give me Either<Throwable, Tuple2<A, B>>, instead it gives me Tuple2<A, B>, which then needs to be producted like I am doing above with parMapN.Satyam Agarwal
09/15/2020, 2:57 PMsimon.vergauwen
09/16/2020, 7:35 AMparMapN was deprecated in IO for parTupledN? In IO we deprecated `parMapN`'s f: (A, B) -> C in favor of f: (Tuple2<A, B>) -> C because that's how it works in Applicative, due to how it's derived from other combinators in interface Applicative. So we aligned the signatures between Concurrent#parMapN & Applicative#mapN.
However in Arrow Fx Coroutines since it's a concrete implementation for suspend we don't have that limitation of deriving from Applicative, so for that reason, we have gone back to the simpler (and slightly more efficient) f: (A, B) -> C signature. So that you can directly apply function references without having to mangle the TupleN types manually in between.simon.vergauwen
09/16/2020, 7:36 AMTuple2<A, B> instead of Either<Throwable, Tuple2<A, B>> is because Throwable is encapsulated in suspend just like it was in IO so instead of IO<Tuple2<A, B>> you now get suspend () -> Tuple2<A, B>.Satyam Agarwal
09/16/2020, 8:04 AMinterface SomeRepo {
suspend fun getId(someId: Int): Either<Throwable, Int>
suspend fun getName(someName: String): Either<Throwable, String>
}
interface AnotherClass {
val someRepo: SomeRepo
suspend fun <A, B> getResult(someName: String, someId: Int): Either<Throwable, Tuple2<Int, String>> {
return parMapN(
suspend { someRepo.getId(someId) },
suspend { someRepo.getName(someName) }
) { a, b -> a.product { b } }
}
}
When I write this with IO :
interface SomeRepo {
fun getId(someId: Int): IO<Int>
fun getName(someName: String): IO<String>
}
interface AnotherClass {
val someRepo: SomeRepo
fun <A, B> getResult(someName: String, someId: Int): IO<Tuple2<Int, String>> {
return IO.parTupledN(
someRepo.getId(someId),
someRepo.getName(someName)
)
}
}Satyam Agarwal
09/16/2020, 8:07 AMsimon.vergauwen
09/16/2020, 11:14 AMIO version is actually the following:
interface SomeRepo {
suspend fun getId(someId: Int): Int
suspend fun getName(someName: String): String
}
interface AnotherClass {
val someRepo: SomeRepo
suspend fun <A, B> getResult(someName: String, someId: Int): Tuple2<Int, String> =
parTupledN(
{ someRepo.getId(someId) },
{ someRepo.getName(someName) }
)
}
If you want the Throwable to Either you can always use Either.catch at any point in time like you would do IO#attempt.Satyam Agarwal
09/16/2020, 11:42 AMsimon.vergauwen
09/16/2020, 12:36 PMThrowable in Either all over the place. Other unexpected exceptions will still be correctly encapsulated in suspend just like IO, aallowing you to safely ignoring them until the edge of the world.
sealed class MyError {
data class Unexcepted(val throwable: Throwable): MyError()
object FailedToRead : MyError()
}
suspend fun someBlockingJavaApi(): Either<MyError, Result> =
Either.catch {
val res = evalOn(IOPool) { javaCall() }
}.mapLeft { exception ->
when(exception) {
is ExpectedCheckedException -> FailedToRead
else -> Unexcepted(exception)
}
}Satyam Agarwal
09/16/2020, 12:57 PMsimon.vergauwen
09/16/2020, 2:05 PM