electronicarts / ea-async

EA Async implements async-await methods in the JVM.
https://go.ea.com/ea-async
Other
1.38k stars 129 forks source link

Wrap return types of methods that use await into CompletableFuture automatically #39

Closed TheMulti0 closed 5 years ago

TheMulti0 commented 5 years ago

Hi! Thanks for the great library.

There's a thing in this library that annoys me when I use it, and hope that you can add. In C#, just like in this library everything after the await keyword is converted into a callback under the hood. In addition, async methods that use the keyword await must return Task (or void, but not recommended), just like in this library where every method that uses the await method needs to return a CompletableFuture. Since when you use the await method you get the desired type on the awaited method, straight ahead, no need to deal with CompletableFutures, but the problem is that you have to return one. I personally just wrap it with CompletableFuture.completedFuture(awaitedValue), but that can be annoying when you have a lot of async methods.

Here's an example:

public CompletableFuture<AudioTrack> search(String query) {
    var track = await(youTubeProvider.searchAsync(query));
    track.supplier = "Example usage";
    track.setDate(LocalTime.now());
    return CompletableFuture.completedFuture(track);
}

Imagine having huge amount of methods just like that. This causes huge frustration and makes the code much longer, since I have to upcast the wrapped value inside the CompletableFuture.

I would be very happy to see the instrumental tool converting a return of any awaited TValue into a CompletableFuture<TValue>. So my code will look like this:

public CompletableFuture<AudioTrack> search(String query) {
    var track = await(youTubeProvider.searchAsync(query));
    track.supplier = "Example usage";
    track.setDate(LocalTime.now());
    return track;
}

The track is automatically wrapped into a CompletableFuture<AudioTrack>.

I hope I managed to express myself and you got my point. Thank you very much! You're saving my life from callback hell!

P.S. Perhaps I'm using it not correctly, I'll be very happy to learn the appropriate way.

JoeHegarty commented 5 years ago

I understand what you're asking for, but I have concerns.

In an ideal world I agree it would be much better for us to be able to just return the type unwrapped, but the problem I see is that an IDE would not know about it. The key thing with EA async right now is that it's perfectly valid Java and the call to await does nothing until instrumentation, so the code appears as valid in whatever IDE you are doing.

So in general I am not sure we can do this without writing plugins for all the IDEs, and that's certainly not on the roadmap currently.

TheMulti0 commented 5 years ago

Thanks for the quick reply! I understand it might be problematic, therefore I am asking, do you think that there is a better way to work with your library and dealing with CompletableFutures less?

JoeHegarty commented 5 years ago

I don't think there is really anything you can do.

EA Async just simply allows you to await on CompletionStage, so in terms of creating the futures etc you just use the standard methods CompletableFuture.completedFuture and similar.

You can of course create better convenience methods, for example in Orbit we have Task.fromValue etc

TheMulti0 commented 5 years ago

I see. Thanks! Are you certain that each method utilizing await must return a CompletableFuture? Cannot those methods even return void? But I will look into Orbit's Tasks.

TheMulti0 commented 5 years ago

Hi @JoeHegarty . Sorry for buzzing you, but did you see my last comment?

JoeHegarty commented 5 years ago

My apologies, has been a crazy week. Methods must return a CompletableFuture/CompletionStage, that is an absolute requirement.

The reason for this is fairly simple:

Obviously there is a lot more complexity with handling exceptions etc, but roughly that's what happens during the bytecode transform.

As such, there is no way in Java to do this kind of operation without returning a future or blocking the method, so all methods must return CompletableFuture.

TheMulti0 commented 5 years ago

Perfect. Thanks!