Skip to content
New issue

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

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

Already on GitHub? # to your account

2.x: emitting nulls from Observable.create() #4492

Closed
marcin-kozinski opened this issue Sep 7, 2016 · 16 comments
Closed

2.x: emitting nulls from Observable.create() #4492

marcin-kozinski opened this issue Sep 7, 2016 · 16 comments
Labels

Comments

@marcin-kozinski
Copy link

It is not possible right now to create an observable that emits nulls using Observable.create(). Emitter's javadoc states @param value the value to signal, not null and in fact when I tried calling emitter.onNext(null) it is checked at runtime and results in a NullPointerException.

Can I get any insight as to why this decision has been taken? And why only in this place, as I believe it is still possible to emit null via for example Observable.just()?

It is a fairly common pattern when you want an observable that emits multiple "events" that don't carry any data. Usually then you create an Observable<Void> and emit nulls in onNext(). For example this is what I tried to write to get an observable of clicks on a view in Android (while @JakeWharton 's RxBinding doesn't have a 2.x release):

public static Observable<Void> clicks(final View view) {
    return Observable.create(emitter -> {
        MainThreadDisposable.verifyMainThread();

        view.setOnClickListener(ignored -> emitter.onNext(null)); // causes NullPointerException at runtime

        emitter.setDisposable(new MainThreadDisposable() {
            @Override
            protected void onDispose() {
                view.setOnClickListener(null);
            }
        });
    });
}

Should I use a different way of creating such observable? Or is there a different pattern altogether for this use case in 2.x?

@akarnokd
Copy link
Member

akarnokd commented Sep 7, 2016

We adopted the Reactive-Streams style of value management which forbids using nulls in the sequences. Use Object instead and emit anything:

public static Observable<Object> clicks(final View view) {
    return Observable.create(emitter -> {
        MainThreadDisposable.verifyMainThread();

        view.setOnClickListener(ignored -> emitter.onNext(ignored)); // works fine

        emitter.setDisposable(new MainThreadDisposable() {
            @Override
            protected void onDispose() {
                view.setOnClickListener(null);
            }
        });
    });
}

@vanniktech
Copy link
Collaborator

vanniktech commented Sep 7, 2016

How about providing a class in RxJava itself which basically provides that ignored value class?

@akarnokd
Copy link
Member

akarnokd commented Sep 7, 2016

Java has a fantastic built-in type and instance that you can ignore at your will: (Integer)1.

@VictorAlbertos
Copy link
Contributor

I agree with @vanniktech. I think that providing a RxJava type which express this intent will lead to more consistent apis.

Because @akarnokd you have suggested to use an Integer/Object, but I was thinking in creating my own Type, like a wrapper for Void, something like Result<Void>.

So I suggest that we should create a new RxJava Type or at least set from now on an official way to deal with this situation.

@JakeWharton
Copy link
Contributor

I do not think this is RxJava's responsibility. Kotlin has Unit and with
Java you have just Object and literally anything. If the point of these
Observables is that the value doesn't matter why are we so concerned about
having a standard value?

On Wed, Sep 7, 2016, 8:42 AM Víctor Albertos notifications@github.com
wrote:

I agree with @vanniktech https://github.com/vanniktech. I think that
providing a RxJava type which express this intent will lead to more
consistent apis.

Because @akarnokd https://github.com/akarnokd you have suggested to use
an Integer/Object, but I was thinking in creating my own Type, like a
wrapper for Void, something like Result.

So I suggest that we should create a new RxJava Type or at least set from
now on an official way to deal with this situation.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#4492 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAEEETSQ0R4yOL3GwG_2_JzcjvECh7UAks5qnrE5gaJpZM4J2wZ9
.

@VictorAlbertos
Copy link
Contributor

Precisely, to make completely clear that the value doesn't matter without needing to check the docs.

@JakeWharton, what are you planning to do regarding this matter for RxBinding? Will be Observable<Object>instead of Observable<Void>?

@JakeWharton
Copy link
Contributor

Probably

On Wed, Sep 7, 2016 at 8:52 AM Víctor Albertos notifications@github.com
wrote:

Precisely, to make completely clear that the value doesn't matter without
needing to check the docs.

@JakeWharton https://github.com/JakeWharton, what are you planning to
do regarding this matter for RxBinding? Will be Observableinstead
of Observable?


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#4492 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAEEET9WHRtHix8WIR8iS8Luxw0hcKLVks5qnrOYgaJpZM4J2wZ9
.

@pakoito
Copy link

pakoito commented Sep 7, 2016

Not worth adding to the RxJava 2 branch, but I suspect I'll end up using something similar to this in my client libraries:

public final class Ignore {
  private final Ignore(){}

  public static final Ignore GET = new Ignore();
}

Just because I want to encode the behaviour as a type and it always succeeds equality checks as Void did, even if the cost is a tiny bit higher than using any other constant.

@VictorAlbertos
Copy link
Contributor

I think more users are going to feel this gap too, and they will eventually create his own type. Indeed, I'm thinking to create something like that for my own libraries and client code.

But it would be better if someone with enought reputation/popularity -like @JakeWharton or @akarnokd - created a library to fill this gap.

@akarnokd
Copy link
Member

akarnokd commented Sep 7, 2016

I'm a bit fed up with all these reactive types because each new one shamed out of me doubles the work I have to do for free and overtime. There are infinite amount of base reactive types possible with all sorts of property combinations, no-valued types, multi-valued onNext, with or without backpressure, multiple onErrors, etc.

@JakeWharton
Copy link
Contributor

JetBrains (extremely reputable and popular) already created a library
called kotlin-runtime that has Unit and Unit.INSTANCE!

On Wed, Sep 7, 2016 at 10:46 AM Víctor Albertos notifications@github.com
wrote:

I think more users are going to feel this gap too, and they will
eventually create his own type. Indeed, I'm thinking to create something
like that for my own libraries and client code.

But it would be better if someone with enought reputation/popularity -like
@JakeWharton https://github.com/JakeWharton or @akarnokd
https://github.com/akarnokd - created a library to fill this gap.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#4492 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAEEEdw4ecjPDnYItzPPH7YUUy8S-FUtks5qns5PgaJpZM4J2wZ9
.

@abersnaze
Copy link
Contributor

@akarnokd I don't think the Ignore class was intended to be new reactive type. I think it was intended to be non null replacement for the Void type so code that uses Observable<Void> could be changed to Observable<Ignore> when using 2.x.

@akarnokd
Copy link
Member

It's the same problem as with Pairs, Tuples and function combinators; we don't use them in the library and would just clutter the namespaces for projects which use something else anyway. You can use your own 'ignored' type as you see fit.

public enum MyIgnored {
   PLEASE_IGNORE_ANY_VALUE_OF_ME;
}

@vietj
Copy link

vietj commented Oct 15, 2016

I understand how a stream of null values can be emitted using a type that represents null.

I don't understand how a stream of values that might have null instance emitted should be handled without loosing type safety as Java does not handle union types.

@akarnokd
Copy link
Member

@vietj Use Optional<T>.

@vietj
Copy link

vietj commented Oct 15, 2016

@akarnokd seems the best alternative indeed

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

No branches or pull requests

8 participants