Flatten future of future?

61 views
Skip to first unread message

Soonil Nagarkar

unread,
Feb 23, 2024, 3:50:51 PMFeb 23
to guava-discuss
I feel like I'm missing something simple here, but I'm unable to come up with any way to solve my problem... I have a ListenableFuture<ListenableFuture<T>>. I want to convert that to ListenableFuture<T>. How can I do so?

Luke Nezda

unread,
Feb 23, 2024, 4:35:16 PMFeb 23
to Soonil Nagarkar, guava-discuss
Have you asked this on stackoverflow?

On Fri, Feb 23, 2024 at 2:50 PM 'Soonil Nagarkar' via guava-discuss <guava-...@googlegroups.com> wrote:
I feel like I'm missing something simple here, but I'm unable to come up with any way to solve my problem... I have a ListenableFuture<ListenableFuture<T>>. I want to convert that to ListenableFuture<T>. How can I do so?

--
guava-...@googlegroups.com
Project site: https://github.com/google/guava
This group: http://groups.google.com/group/guava-discuss
 
This list is for general discussion.
To report an issue: https://github.com/google/guava/issues/new
To get help: http://stackoverflow.com/questions/ask?tags=guava
---
You received this message because you are subscribed to the Google Groups "guava-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to guava-discus...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/guava-discuss/bde6bd39-23ce-4746-99ed-fcecbc697f63n%40googlegroups.com.

Colin Decker

unread,
Feb 23, 2024, 5:12:34 PMFeb 23
to Luke Nezda, Soonil Nagarkar, guava-discuss
Luke is right that StackOverflow is a better place to ask this kind of thing. That said, I'm not an expert in this area but it sounds to me like the kind of thing `AsyncCallable` and `AsyncFunction` are for. See for example `Futures.transformAsync`, which could be used with an identity function to do what you want. Though if you can, it would probably be better to use `AsyncCallable` earlier, i.e. submitting your task using `Futures.submitAsync` so you never get the nested future.



--
Colin Decker | Software Engineer | cgde...@google.com | Java and Kotlin Ecosystem Team

j...@durchholz.org

unread,
Feb 26, 2024, 4:26:58 AMFeb 26
to guava-...@googlegroups.com
Approach 1, wrap it:

You can write a static function

<T> ListenableFuture<T> unwrapListenableFuture
(ListenableFuture<ListenableFuture<T>> nested)
{
return new Wrapper(nested);
}

where Wrapper could be some nested (even anonymous) class which
implements the interface using the "nested" object (implementations
should be straightforward).

Downsides:
It adds an additional case for approach 2, so if you're forced to
approach 2 for other reasons, you won't want this approach.
It increases overall complexity of the project, and future code changes
may turn this from a mere annoyance into a problem.

Advantage: It is guaranteed to work.


Approach 2, crowbar it:

If there is a known list of classes that implement
ListenableFuture<ListenableFuture<T>>, you may be able to cast to the
implementing class; such a class will typically contain a member of type
ListenableFuture<T> which you can extract.

Downside:
This can fail if module boundaries are enforced.
Not many projects actually do this, but it's going to become more
commonplace over time.


Approach 3, avoid it:

That said, having a ListenableFuture<ListenableFuture<T>> anywhere is a
code smell; if you control the code that constructs such an object, you
should change it to just return a ListenableFuture<T> and avoid having
to write that unwrapListenableFuture function.

Downside:
The change may be impossible, because the code that generates the
ListenableFuture<ListenableFuture<T>> is controlled by somebody else who
will not make the change for you, or if you're the person controlling
that code, due to time constraints or because you can't (easily) change
the API.


Hope this helps.
Regards,
Jo
Reply all
Reply to author
Forward
0 new messages