i'm curious about the async builder --- in <this>...
# getting-started
x
i'm curious about the async builder --- in this example (Parallel decomposition section) the tutorial uses
Copy code
async {
			client.get().uri("/userdetail1/${user.login}")
				.accept(APPLICATION_JSON)
				.awaitExchange().awaitBody<UserDetail1>()
		}
am I wrong to think you could just do
Copy code
val asyncDetail1 = client.get().uri("/userdetail1/${user.login}")
				.accept(APPLICATION_JSON)
		val asyncDetail2 = client.get().uri("/userdetail2/${user.login}")
				.accept(APPLICATION_JSON)
		UserWithDetails(user, asyncDetail1.awaitExchange().awaitBody<UserDetail1>(), asyncDetail2.awaitExchange().awaitBody<UserDetail2>())
with the exact same result?
j
It's not the same, it's the whole point of this section. Wrapping in
async { .. }
makes the block of code asynchronous. This means that the next piece of code will run concurrently with this
async
block. In short, using 2
async
and then awaiting both allows to make those 2 calls concurrently (and possibly in parallel on the right dispatcher)
x
@Joffrey hmmm, but if client.get() returns a Mono (so it's async, too), shouldn't the call with no await work the same way? like if you throw that in a debugger, asyncDetail2 call wont wait until asyncDetail1 is fetched, no?
j
Oh my bad, I overlooked that you had removed the
awaitX
parts in the 2 calls
I'm assuming the goal is to remove usages of
Mono
at some point and migrate to coroutines, so there
client.get()
could instead be turned into suspending functions. It's kinda one step further towards the migration.
x
ah, I understand, but functionally it should be the same, right?
j
I'm not very familiar with how
Mono
and the rest of the reactive framework works, but there may also be a difference in how both handle errors. With structured concurrency, if one of the client calls fails, it cancels the other and throws. In particular if the second call fails, the first will be canceled right away and the function overall will throw. In the case of the pure
Mono
approach that you suggested, if we assume the first call succeeds in 5 seconds, but the second fails almost immediately, I believe you will still have to wait for the first call to complete before the second await can throw (but that's an assumption)
x
i see, very cool, thank you!
i'll try the fails example locally, I am curious about it. I will say kotlin's approach to asynchronous code is fantastic and feels good to use compared to java's
j
I also find coroutines awesome, and particularly nice on the use site 🙂 especially when compared to Java's futures, callbacks, and threads
x
yep! java's version reminds me of node's callback hell