Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

R3 Observable as UniTask never completes #576

Open
Antoshidza opened this issue Apr 25, 2024 · 4 comments
Open

R3 Observable as UniTask never completes #576

Antoshidza opened this issue Apr 25, 2024 · 4 comments

Comments

@Antoshidza
Copy link

Antoshidza commented Apr 25, 2024

UnityEngine.Debug.Log($"start to await num selection");
await Observable.EveryUpdate() // never completes
    .Select(_ => GetNumberKeyPressed())
    .Where(numberKey => numberKey != -1)
    .AsSystemObservable()
    .ToUniTask();
// await UniTask.Delay(1000); // works
UnityEngine.Debug.Log($"await completed"); // never happens

In R3 there is only Observable class so I can't use .ToUniTask() directly, instead I try to use .AsSystemObservable before but such code never completed. Observable query itself also works when subscribed with classic R3 .Subscribe method. At the same time simple Delay works perfectly. Am I doing something wrong or there is no way to treat R3 observable as UniTask?

Unity 2023.2.15
R3 1.1.11
UniTask 2.5.4

@Antoshidza
Copy link
Author

if .ToUniTask(true) called with true passed then all works well. If look inside this extension method it reveals that if firstValue parameter is true then FirstValueToUniTaskObserver is created instead of ToUniTaskObserver. The difference as I can tell is when this two IObservable calls TrySetResult on theirs UniTaskCompletionSource<T> promise. FirstValueToUniTaskObserver do it straightaway in OnNext and ToUniTaskObserver do it inside OnComplete. So it seems that OnComplete doesn't get called.

@neuecc
Copy link
Member

neuecc commented Apr 30, 2024

I see. I'd like to think about that conversion path, but semantically,
how about converting R3 to Task and then having it converted to UniTask?

@Antoshidza
Copy link
Author

Antoshidza commented Apr 30, 2024

I see. I'd like to think about that conversion path, but semantically, how about converting R3 to Task and then having it converted to UniTask?

Does this Observable<T> -> Task<T> -> UniTask<T> available today? I see R3 has extensions like FirstAsync which I believe allow to await first callback.

If yes then it is already good enough to bridge R3 and UniTask. But as I understand UniTask stands for optimization and integration into unity's player loop. When we first create Task<T> from R3 we ruin optimization part I believe. Am I wrong?

Obviously R3 nor UniTask shouldn't know about each other, which is why we need some bridge. Guess separate package would be overkill for such little extension. Maybe some code gist would be enough for folks like me who want to use those packages in a tight couple.

@neuecc
Copy link
Member

neuecc commented May 1, 2024

In R3, FirstAsync or LastAsync allows you to decide which way to wait.
Usually in conver to Task, the code expects Last, but First is often more useful.

It is natural to want to convert R3 to an awaitable type (that is why FirstAsync and LastAsync exist).
It is true that there is an overhead due to not being able to convert directly, but we do not think it is large enough to be a problem in situations where this is required.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants