Scala with Futures:
import java.util.UUID
import scala.concurrent.Future
trait User {
def isAdmin: Boolean
def id: UUID
}
trait Profile {
val accessLevel: Int
}
def createUser(user: User): Future[User] = ???
def createProfile(userId: UUID, profile: Profile): Future[Profile] = ???
def createAdminRights(admin: User, accessLevel: Int): Future[Unit] = ???
def create(newUser: User, newProfile: Profile): Future[Unit] = {
for {
user <- createUser(newUser)
profile <- createProfile(user.id, newProfile)
_ <- if (user.isAdmin) {
createAdminRights(user, profile.accessLevel)
} else {
Future.unit
}
} yield ()
}
object Main {
import scala.concurrent._
import scala.concurrent.duration._
def main(args: Array[String]): Unit = {
val user: User = ???
val profile: Profile = ???
Await.result(create(user, profile), 10.seconds)
}
}
Kotlin with Coroutines:
import java.util.*
interface User {
val isAdmin: Boolean
val id: UUID
}
interface Profile {
val accessLevel: Int
}
suspend fun createUser(user: User): User = TODO()
suspend fun createProfile(userId: UUID, profile: Profile): Profile = TODO()
suspend fun createAdminRights(admin: User, accessLevel: Int): Unit = TODO()
suspend fun create(newUser: User, newProfile: Profile) = {
val user = createUser(newUser)
val profile = createProfile(user.id, newProfile)
if (user.isAdmin) {
createAdminRights(user, profile.accessLevel)
}
}
object Main {
fun main(args: Array<String>) = runBlocking {
val user: User = TODO()
val profile: Profile = TODO()
create(user, profile)
}
}
Scala futures can written in the style of coroutines using async/await.
The newer -Xasync compiler flag, which replaces the traditional macro approach, generalizes to monads other than Future.
And there are various other projects providing/generalizing continuation passing style in different ways. Cats, for example, has a CPS library that would work with Monix.