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

2.x: Consumer contract is violated when using doOnEvent #5442

Closed
ansman opened this issue Jun 26, 2017 · 13 comments · Fixed by #5447
Closed

2.x: Consumer contract is violated when using doOnEvent #5442

ansman opened this issue Jun 26, 2017 · 13 comments · Fixed by #5447

Comments

@ansman
Copy link
Contributor

ansman commented Jun 26, 2017

The following code showcases the problem:

Completable.complete()
  .doOnEvent(t -> {})

t in this case is annotated with @NonNull but it will be null since the completable completes.

This is a real pain in Kotlin since the following code crashes in runtime:

Completable.complete()
  .doOnEvent {}
@sakuna63
Copy link

sakuna63 commented Jun 27, 2017

BiConsumer is also violated when using Single#subscribe. Either value or throwable will be null.

@akarnokd
Copy link
Member

Removing the annotation from Consumer may affect all other places where it is not-null. Can you override the annotation somehow at the call site?

@sakuna63 BiConsumer doesn't have the annotations.

@svenjacobs
Copy link

I just stumbled upon this while using Kotlin, too. However I wonder how a function argument annotated with @NonNull can ever be null? Even in Java this should be problematic as the contract is broken.

@akarnokd
Copy link
Member

Maybe RxKotlin has/could have workarounds for these. /cc @thomasnield

@sakuna63
Copy link

sakuna63 commented Jun 27, 2017

Sorry, I read old source code.
The annotations have already been removed at #5257

@svenjacobs
Copy link

This was introduced with #5023

@svenjacobs
Copy link

Removing the annotation from Consumer may affect all other places where it is not-null. Can you override the annotation somehow at the call site?

@akarnokd If there's just one call that passes null to the function then imho the argument must be annotated with @Nullable and not @NonNull. What's the point of @NonNull when it can be null?

@ansman
Copy link
Contributor Author

ansman commented Jun 27, 2017

@akarnokd no, the problem cannot be remidied in kotlin which completely prevents the usage of that operator in kotlin.
Removing the annotation won't make it nullable though, it would just mean that we don't know the nullability status which is the case too. Why is it important to keep it? I see very little harm in removing it and as @svenjacobs said the contract is broken in java too. If I were to null check it in java I would probably get lint warning telling me to remove the null check.
Ideally there should be multiple interfaces like @rharter suggested in the issue for BiFunction

@akarnokd
Copy link
Member

If you can think you can resolve this with minimal changes, PR welcome.

@svenjacobs
Copy link

By the way this issue emerged with the release of Kotlin 1.1.3. Although @NonNull has already been added months ago it seems that the compiler/runtime library of Kotlin 1.1.3 became stricter in regards to nullability.

@ansman
Copy link
Contributor Author

ansman commented Jun 27, 2017

Ah, that explains why I just recently starting having problems.

@artem-zinnatullin
Copy link
Contributor

Huh, I thought implementing Consumer interface manually with correct nullability will help:

Completable
        .fromCallable {  }
        .doOnEvent(object : Consumer<Throwable> {
            override fun accept(t: Throwable?) { // Error: 'accept' overrides nothing
                println("event: $t")
            }
        })
        .subscribe()

But Kotlin compiler (1.1.3-eap34) does not even let such code to compile, so there is probably no clear way to solve this in Kotlin without using Java code.

@dhruvj
Copy link

dhruvj commented Apr 5, 2018

Is doOnEvent the only operator that needs a Consumer that accepts Nullable data? If so, why remove @NonNull which is fairly useful annotation for most of the other operators? Why not have a different, let's say, Consumer2 specifically for doOnEvent and such operators?

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

Successfully merging a pull request may close this issue.

6 participants