[
https://issues.apache.org/jira/browse/GROOVY-9381?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18030853#comment-18030853
]
Daniel Sun edited comment on GROOVY-9381 at 10/18/25 2:46 PM:
--------------------------------------------------------------
[~blackdrag] I wish I have fully understood what you are thinking about:
{quote}how are return values handled -> shown already
{quote}
{{async}} wraps the return value in a "Promise" object, and {{await}} unwraps
it.
{quote}how are exceptions handled
{quote}
This is one of the biggest advantages of {{{}async/await{}}}. Exceptions are
handled by standard {{try...catch}} blocks, making asynchronous error handling
look identical to synchronous error handling.
*How it works:*
# When an exception is thrown inside an {{async}} function, the "Promise"
object transitions to a "rejected" state and {*}stores the exception{*}.
# When you {{await}} that promise, the {{await}} keyword checks the promise's
state. If it's "rejected," {{await}} *re-throws the stored exception* at that
exact line.
{code:java}
async processUserData() {
try {
// re-throw the stored exception
def user = await fetchUserData(1)
println "Got user: ${user.name}"
} catch (UserNotFoundException e) {
// Error handling is in a familiar, standard catch block.
println "Caught error: ${e.message}"
}
}
{code}
{quote}Can I simulate async for a function/method by using a special return
type?
{quote}
Yes, this is exactly how async/await works under the hood. We can use any
return type implementing {{Awaitable}}
{quote}since Java 21 what is the underlying threading model? lightweight
threads or normal threads? Can we switch between them and so on
{quote}
If Virtual Threads feature is available, use it by default, or use the platform
thread instead. We could set some option to switch between them.
{quote}
Do we also want to support ES2018 "for async"? RxJava processing would be
incomplete without some kind of stream processing for asyncs.
{quote}
Yes. For example,
{code:java}
(async {
await for (r in createAsyncIterable(['a', 'b'])) {
println r
}
})() // call the async closure
{code}
{quote}How could we integrate with for example Spring-Async?
{quote}
The return type of method marked with {{@Async}} is
{{{}java.util.concurrent.Future{}}}.
In order to integrate with existing framework gracefully, we could make Groovy
Promise implement both {{Awaitable}} and {{Future}} interfaces.
{code:java}
@Async
public Future<String> processData() {
return new groovy.util.concurrent.Promise<String>("hello");
}
{code}
was (Author: daniel_sun):
[~blackdrag] I wish I have fully understood what you are think about:
{quote}how are return values handled -> shown already
{quote}
{{async}} wraps the return value in a "Promise" object, and {{await}} unwraps
it.
{quote}how are exceptions handled
{quote}
This is one of the biggest advantages of {{{}async/await{}}}. Exceptions are
handled by standard {{try...catch}} blocks, making asynchronous error handling
look identical to synchronous error handling.
*How it works:*
# When an exception is thrown inside an {{async}} function, the "Promise"
object transitions to a "rejected" state and {*}stores the exception{*}.
# When you {{await}} that promise, the {{await}} keyword checks the promise's
state. If it's "rejected," {{await}} *re-throws the stored exception* at that
exact line.
{code:java}
async processUserData() {
try {
// re-throw the stored exception
def user = await fetchUserData(1)
println "Got user: ${user.name}"
} catch (UserNotFoundException e) {
// Error handling is in a familiar, standard catch block.
println "Caught error: ${e.message}"
}
}
{code}
{quote}Can I simulate async for a function/method by using a special return
type?
{quote}
Yes, this is exactly how async/await works under the hood. We can use any
return type implementing {{Awaitable}}
{quote}since Java 21 what is the underlying threading model? lightweight
threads or normal threads? Can we switch between them and so on
{quote}
If Virtual Threads feature is available, use it by default, or use the platform
thread instead. We could set some option to switch between them.
{quote}
Do we also want to support ES2018 "for async"? RxJava processing would be
incomplete without some kind of stream processing for asyncs.
{quote}
Yes. For example,
{code:java}
(async {
await for (r in createAsyncIterable(['a', 'b'])) {
println r
}
})() // call the async closure
{code}
{quote}How could we integrate with for example Spring-Async?
{quote}
The return type of method marked with {{@Async}} is
{{{}java.util.concurrent.Future{}}}.
In order to integrate with existing framework gracefully, we could make Groovy
Promise implement both {{Awaitable}} and {{Future}} interfaces.
{code:java}
@Async
public Future<String> processData() {
return new groovy.util.concurrent.Promise<String>("hello");
}
{code}
> Support async/await like ES7
> ----------------------------
>
> Key: GROOVY-9381
> URL: https://issues.apache.org/jira/browse/GROOVY-9381
> Project: Groovy
> Issue Type: New Feature
> Reporter: Daniel Sun
> Priority: Major
>
> Here is an example to show proposed syntax and backend API(Java's
> {{CompletableFuture}} or GPars's {{{}Promise{}}}), but I think it's better
> for Groovy to have its own {{Promise}} to decouple with Java API because
> async/await as a language feature should be as stable as possible.
> {{async}} will generate the {{Awaitable}} instance such as Groovy {{Promise}}
> implementing the {{Awaitable}} interface, and {{await}} can wait for any
> {{Awaitable}} instance to complete and unwrap it for the result.
> {code:java}
> /**
> * 1. An async function that simulates a network API call.
> * The 'async' keyword implies it runs asynchronously without blocking.
> */
> async fetchUserData(userId) {
> println "Starting to fetch data for user ${userId}..."
>
> // Simulate a 1-second network delay.
> Thread.sleep(1000)
>
> println "Fetch successful!"
> // The 'async' function implicitly returns a "CompletableFuture" or
> "Promise" containing this value.
> return [userId: userId, name: 'Daniel']
> }
> /**
> * 2. An async function that uses 'await' to consume the result.
> */
> async processUserData() {
> println "Process started, preparing to fetch user data..."
>
> try {
> // 'await' pauses this function until fetchUserData completes
> // and returns the final result directly.
> def user = await fetchUserData(1)
>
> println "Data received: ${user}"
> return "Processing complete for ${user.name}."
>
> } catch (Exception e) {
> return "An error occurred: ${e.message}"
> }
> }
> // --- Execution ---
> println "Script starting..."
> // Kick off the entire asynchronous process.
> def future = processUserData()
> // This line executes immediately, proving the process is non-blocking.
> println "Script continues to run while user data is being fetched in the
> background..."
> def result = future.get()
> println "Script finished: ${result}"
> {code}
> Use async/await with closure or lambda expression:
> {code:java}
> // use closure
> def
> {code}
> {color:#910091}c {color}
> {code:java}
> = async {
> println "Process started, preparing to fetch user data..."
>
> try {
> // 'await' pauses this function until fetchUserData completes
> // and returns the final result directly.
> def user = await fetchUserData(1)
>
> println "Data received: ${user}"
> return "Processing complete for ${user.name}."
>
> } catch (Exception e) {
> return "An error occurred: ${e.message}"
> }
> }
> def future = c(){code}
> {code:java}
> // use lambda expression
> def
> {code}
> {color:#910091}c {color}
> {code:java}
> = async () -> {
> println "Process started, preparing to fetch user data..."
>
> try {
> // 'await' pauses this function until fetchUserData completes
> // and returns the final result directly.
> def user = await fetchUserData(1)
>
> println "Data received: ${user}"
> return "Processing complete for ${user.name}."
>
> } catch (Exception e) {
> return "An error occurred: ${e.message}"
> }
> }
> def future = c() {code}
--
This message was sent by Atlassian Jira
(v8.20.10#820010)