^^^ I do understand the concept of instantiating a...
# arrow
f
^^^ I do understand the concept of instantiating an IO, building it up, and finally "running" it does that mean that, in the context of a jersey endpoint, it would have to look like this?
Copy code
class UserResource (private val userDao: UserDao) {

  @POST
  fun post(CreateUserRequest createUserRequest){
    return IO
      .fx {
        userDao.create()
    }
  }.runUnsafe something something
  .toEither()
  .fold({ left ->
    Response.serverError()
  },{ right ->
    Response.success(right)
  })
}
s
In Kotlin we live in the world of
suspend
, which has the same capabilities as
IO
. Where
suspend
has support in the compiler, and thus has much nicer performance and syntax in the Kotlin language. Therefore
suspend
was chosen over
IO
, and
IO
is being deprecated. That being said, when you're doing something like
useDoa.createUser(request)
there is typically scheduling involved to go to an different
Thread
, or rather pool, for doing blocking tasks like network request or database queries. Therefore you want to use
suspend
which has such capabilities. This would change your signature to:
suspend fun create(request: InternalCreateUserRequest): Either<IError, User>
. Now that the function is
suspend
, and has the capabilities of going
async
you can access a bunch of concurrency operators in KotlinX Coroutines or Arrow Fx Coroutines and can rewrite your code to.
Copy code
override fun create(request: InternalCreateUserRequest): Either<IError, User> =
        Either.catch {
          withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
            userDao.createUser(request) //returns User but can throw
          }
        }.mapLeft { throwable ->
            InternalServerError("Failed to create user", throwable)
        }
Which with
IO
is the equivalent of
IO<Either<IError, User>>
, and this already shows that
suspend
is much more superior in Kotlin than
IO
. This would change your usage site to:
Copy code
@POST
  fun post(CreateUserRequest createUserRequest): Response = runBlocking {
  create(createUserRequest.toInternal())
  .fold({ left ->
    Response.serverError()
  },{ right ->
    Response.success(right)
  })
}
Here
runBlocking
from KotlinX Coroutines is the equivalent of
unsafeRunXXX
from
IO
. It takes a lazy
suspend
function and runs it and rethrows any uncaught errors. The idea in FP is that if in your application you use
suspend
that it should bubble all the way to the edge of your application. In this case your
@Post
function because that's the outer edge of your code. Ideally you'd use a framework that supports
suspend
so you don't even ever call
runBlocking
.
Ktor
has such capabilities, and Spring WebFlux also. Doing so protects you from calling suspend functions from non-suspend functions. Or in other words it protects you from calling side-effecting functions from pure functions.
๐Ÿ” 2
๐Ÿ‘๐Ÿพ 1
I hope that helps ๐Ÿ™‚
๐Ÿ‘ 1
i
Thanks for taking time to explain in details.
๐Ÿ‘ 1
f
@simon.vergauwen can't thank you enough for that excellent explanation, i get it now!
๐Ÿ‘ 1