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

Implement LambdaConsumerIntrospection #5590

Merged
merged 10 commits into from
Sep 12, 2017

Conversation

ZacSweers
Copy link
Contributor

Followup from #5569, and allows you to introspect if the resulting observer has missing error consumption and subsequently supplies a default (throwing) one.

Followup from ReactiveX#5569, and allows you to introspect if the resulting observer has missing error consumption and subsequently supplies a default (throwing) one.
@ZacSweers
Copy link
Contributor Author

Wasn't sure how you'd want to do the naming. Can work on adding some tests if this looks good, wanted to get something up for API review early


/**
* An interface that indicates that the implementing type has default implementations for error consumption.
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@since 2.1.4 - experimental

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -101,4 +104,9 @@ public void dispose() {
public boolean isDisposed() {
return get() == DisposableHelper.DISPOSED;
}

@Override
public boolean hasMissingErrorConsumer() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A test would be great.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@akarnokd
Copy link
Member

akarnokd commented Sep 6, 2017

The naming is fine with me.

@akarnokd akarnokd added this to the 2.2 milestone Sep 6, 2017
@codecov
Copy link

codecov bot commented Sep 6, 2017

Codecov Report

Merging #5590 into 2.x will increase coverage by 0.08%.
The diff coverage is 100%.

Impacted file tree graph

@@             Coverage Diff              @@
##                2.x    #5590      +/-   ##
============================================
+ Coverage     96.15%   96.23%   +0.08%     
- Complexity     5827     5836       +9     
============================================
  Files           632      632              
  Lines         41459    41465       +6     
  Branches       5742     5742              
============================================
+ Hits          39863    39904      +41     
+ Misses          638      621      -17     
+ Partials        958      940      -18
Impacted Files Coverage Δ Complexity Δ
...nternal/observers/CallbackCompletableObserver.java 100% <100%> (ø) 11 <2> (+2) ⬆️
...o/reactivex/internal/observers/LambdaObserver.java 100% <100%> (ø) 14 <2> (+2) ⬆️
...nternal/operators/maybe/MaybeCallbackObserver.java 100% <100%> (ø) 9 <2> (+2) ⬆️
...vex/internal/observers/ConsumerSingleObserver.java 100% <100%> (ø) 9 <2> (+2) ⬆️
...x/internal/observers/EmptyCompletableObserver.java 100% <100%> (ø) 8 <1> (+1) ⬆️
...activex/internal/subscribers/LambdaSubscriber.java 100% <100%> (ø) 16 <2> (+2) ⬆️
...a/io/reactivex/internal/util/QueueDrainHelper.java 58.86% <0%> (-4.26%) 31% <0%> (-3%)
.../internal/operators/flowable/FlowableInterval.java 94.44% <0%> (-2.78%) 3% <0%> (ø)
...activex/internal/observers/QueueDrainObserver.java 61.53% <0%> (-2.57%) 12% <0%> (-1%)
.../io/reactivex/disposables/CompositeDisposable.java 97.24% <0%> (-1.84%) 39% <0%> (-1%)
... and 27 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c43229b...500df33. Read the comment docs.

@ZacSweers
Copy link
Contributor Author

Should I add this to other types' observers too? Or do you want to start with this first?

@akarnokd
Copy link
Member

akarnokd commented Sep 7, 2017

Should I add this to other types' observers too?

That would be great!

@artem-zinnatullin
Copy link
Contributor

Btw @hzsweers, you can solve this right now by overriding (via reflection) io.reactivex.internal.functions.Functions#ON_ERROR_MISSING with Consumer<Throwable> implementation that'll throw error instead of delivering it to the RxJavaPlugins

Although current WIP looks fine for the most part 👍

@ZacSweers
Copy link
Contributor Author

yeah I'd prefer something in the public API :).

@akarnokd should there be a separate HasDefaultErrorConsumer for LambdaSubscriber for symmetry? Or just reuse?

@ZacSweers
Copy link
Contributor Author

Just reused for now, let me know if you want me to make it separate.

I think I've covered the other observer possibilities, let me know if there's any others I should cover

* @since 2.1.4 - experimental
*/
@Experimental
public interface HasDefaultErrorConsumer {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should find a better name for this interface for several reasons:

  1. HasDefaultErrorConsumer sounds like marker interface that you need to use with instanceof to get boolean result.
  2. Interface HasDefaultErrorConsumer and method name hasMissingErrorConsumer() are inconsistent.
  3. Extensibility — do we plan to extend it with other functions to check onNext/onComplete implementations?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd definitely get rid of "default" and "missing" from both. The negated method is really confusing. There's already Has* types which do similar things so I don't agree that it needs changed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, last sentence dropped from my comment for some reason.

Depending on answer to №3 I have following interface names on my mind ObserverIntrospection/SubscriberIntrospection or ErrorConsumerIntrospection, hope someone has better suggestions :)

The negated method is really confusing.

Huh, indeed! Didn't notice that until you pointed

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I let you people work out the naming.

Copy link
Contributor Author

@ZacSweers ZacSweers Sep 8, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for the method, how about just a simple isNotImplemented() or isThrowing()?

Assuming the interface itself gets named HasErrorConsumer?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

People will most likely mistreat CompositeObserver and think of it as of a combination of observers because that's how CompositeDisposable and CompositeException work.

ObserverInstrumentation/ObserverIntrospection? Such a name also more clearly delivers the intention of consume-only public API

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Composite is misleading and will show up in content assist when the developer types Composite

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to get to the disposable/exception variant mentioned.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd call it LambdaConsumerIntrospection and hasCustomOnError()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good points. The Introspection moniker feels off to me, mostly because I consider introspection an act and don't necessarily think of it as a noun/type at first. I don't know what a better word would be though. Updated in bae194c

}

@Test
public void isNotMissingErrorConsumer() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: doesNotHaveMissingErrorConsumer?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made them clearer in 500df33

@ZacSweers
Copy link
Contributor Author

I agree the names could be better, will update tomorrow

@ZacSweers
Copy link
Contributor Author

Ok I've updated the tests and the naming based on CR. The only remaining bit I think is whether or not to use a global introspection interface or make one per observer for better parity. Thoughts?

@artem-zinnatullin
Copy link
Contributor

use a global introspection interface or make one per observer for better parity. Thoughts?

Depends on which level of per observer you're talking about. Hopefully, not about all internal implementations :)

I'd create an interface per Rx-type, so you could hook into these RxJavaPlugins callbacks:

screen shot 2017-09-09 at 18 55 57

ie: MaybeObserverIntrospection, FlowableSubscriberIntrospection, SingleObserverIntrospection, ObservableObserverIntrospection, CompletableObserverIntrospection.

Because if we'll decide to add introspection API for other callbacks like onNext and onComplete in future, some of them will not make sense for types like Completable and Single and naming won't match their callbacks if we go with same interface for all types.

LambdaConsumerIntrospection seems too impl-specific name, I realise that the only way RxJava can understand that ie error handler is default one is to rely on subscribe() calls that accept lambdas. But name still feels kinda wrong and too specific. Just my 2 satoshis.

@ZacSweers
Copy link
Contributor Author

Yeah I meant per-type. I think the name is fine as a specific thing since it's only applicable to composed observers like lambdaobserver. Lambda itself might not be best since that naming convention seems to only exist for Observable and Flowable

@akarnokd
Copy link
Member

I think there is no need to have 5 versions of the same interface; there is always the Subscriber/Observer type discoverable:

public static void errorNotImplemented(Object target) {
    if (target instanceof LambdaConsumerIntrospection) {
        if (target instanceof SingleObserver) {
            // ...
        }
        if (target instanceof Subscriber) {
            // ...
        }
    }
}

@ZacSweers
Copy link
Contributor Author

that works for me. I think this PR is complete then

@ZacSweers ZacSweers changed the title Implement HasDefaultErrorConsumer Implement LambdaConsumerIntrospection Sep 10, 2017
* implementation is missing an error consumer and thus using a throwing default implementation.
*/
@Experimental
boolean hasCustomOnError();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we provide hasDefaultOnError() instead? cc @JakeWharton

Because if you think about it from RxJava perspective — that's what library can say about itself: is something has a default value/implementation in compare to what library thinks is default.

hasCustomOnError() basically checks for hasDefaultOnError() and then negates the result which is kinda confusing.

TL;TR: "custom" in the API feels wrong, but maybe it's just me :)

@artem-zinnatullin
Copy link
Contributor

@akarnokd questionable decision about types, Single and Completable might be inconsistent with future addition of hasDefaultOnNext() and hasDefaultOnComplete() changes in the interface.

up2u of course

@akarnokd
Copy link
Member

If you want to hijack those consumer types, you already know the target type and which signal types it can deliver. Therefore, if they implement the same broad interface, the impossible methods can return false or throw an UnsupportedOperationException.

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

Successfully merging this pull request may close these issues.

4 participants