Skip to content

3.x: Split the library into two or adding types for symmetry #4564

@JakeWharton

Description

@JakeWharton

It may be far too late in the release cycle for this, but in writing an outline for a presentation on RxJava 2 for the last month I've come to think we're erroneously shipping two libraries as one.

RxJava 2 currently has two nearly disjoint pieces:

  • Flowable and FlowableProcessor are a Reactive Streams Publisher and Processor stream type, respectively, which use RS types for subscribing and RS types to control backpressure and unsubscribe notification.
  • Observable, Maybe, Single, Completable, and Subject are custom stream types which use custom types for subscribing, do not have backpressure, and use a custom type for unsubscribe notification.

Aside from explicit conversion functions between the two, these types do not interact. Observable will soon be retrofitted to return more-specific types for certain operators. Flowable also will receive (and already has) some of these more-specific types for certain operators as well, but unlike their enclosing type they do not support backpressure.

When you look at a high-level overview of the library like I have before for normalizing naming, you can clearly see there is a divide.

This divide seems to be rooted in the fact that there's three things pulling RxJava 2 in different directions:

  • Backpressure support was added late to RxJava 1 which resulted in all operators not implementing it. The built-in factories made it harder than it should have been to create backpressure-aware observables around non-Rx sources. This caused MBEs to happen to a lot of people and the desire for non-backpressure types.
  • The RS spec is to be implemented natively for backpressure-aware types.
  • People use and enjoy the four specialized RxJava 1 types: Observable, Single, Completable, and Subject, and want even more: Maybe.

The first two of these are conflicting which is not entirely terrible. If you ignore the third item you'd get four types which we have now: Flowable, Observable, FlowableProcessor, Subject. The third item, however, starts to cause the combinatorial explosion of types.

This is what leads me to believe there are two libraries hiding inside RxJava 2 that, while related, aren't the same:

  1. Flowable, Maybe-like, Single-like, Completable-like, and FlowableProcessor Reactive Streams Publisher types.
  2. Observable, Maybe, Single, Completable, and Subject generic non-backpressure stream types.

As far as I can tell there's three options:

  1. Do nothing. Ship 5 backpressure-free custom types and 2 backpressure-aware RS types in one library with built-in conversion methods across the divide. Live with the fact that the types are asymmetrical and some operators on Flowable do not support backpressure.
  2. Split the library into two. They could either live inside this repository (rxjava-rs and rxjava-nbp) plus an adapter library (rxjava-bridge) for use with to(), or they could be separate and developed/released independently. This doesn't immediately require extra types on the RS side for symmetry. They could be added as needed post-2.0.0.
  3. Add missing types for symmetry between the two inside this one library. This might cause @akarnokd to go crazy because it's non-trivial and few else are qualified and skilled enough to do all the work. Because of the desire to customize the return types of operators it's hard to defer this to post-2.0.0 since it would break compatibility.

I'm curious to hear what others think about this. I'm sorry it didn't dawn on me as a problem sooner.

A final piece of food for thought: if you were implementing RxJava 2 as a brand new library from scratch without the historical context of RxJava 1, what would you want in it?

  • Stream types that implement the Reactive Streams spec.
  • Stream types that do not support backpressure.
  • Customized stream types which model subsets of the event/notification lifecycle.
  • Operators returning customized stream types with the correct backpressure-aware/free context.

Ideally what we ship in RxJava 2 is exactly and only the answers to that question.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions