-
Notifications
You must be signed in to change notification settings - Fork 7.6k
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
3.x: Potential migration/compatibility issues #6606
Comments
RxJava 3 is developed as a replacement to RxJava 2 so yes, you have to wait for libraries depending on such changed APIs to be upgraded. This has been discussed before and keeping everything in the same package is the least problematic path for 3.x as it allows libraries not depending on changed components to keep functioning. With a completely separate package, you have to wait for such libraries to upgrade too.
RxJava 2 will not get any new minor release or new features. Which libraries do you have problems with? |
I have an android app that depends on 12 libraries all depending on rxjava2. I don't understand my path forward. Do I need to wait for all 12 to upgrade if one does and uses a new api? |
Why are the new maven coordinates necessary? Every option not involving
package renaming will be awkward, the least awkward option would just be to
have a major version bump on the existing coordinates. Then you can avoid
making consumers do all this build system finagling just to avoid classpath
conflicts.
…On Wed, Jul 31, 2019, 1:43 PM David Karnok ***@***.***> wrote:
RxJava 3 is developed as a replacement to RxJava 2 so yes, you have to
wait for libraries depending on such changed APIs to be upgraded.
This has been discussed before and keeping everything in the same package
is the least problematic path for 3.x as it allows libraries not depending
on changed components to keep functioning. With a completely separate
package, you have to wait for such libraries to upgrade too.
Add new RxJava 3 operators to RxJava 2.3.x. E.g.
RxJava 2 will not get any new minor release or new features.
Which libraries do you have problems with?
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#6606?email_source=notifications&email_token=AAKMJPR53ZFIK6JWYA6425LQCHFLHA5CNFSM4IIIW5WKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD3IALBI#issuecomment-516949381>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAKMJPQJMF6JSFRJS6DVEA3QCHFLHANCNFSM4IIIW5WA>
.
|
Or, phrased another way, the Maven groupId change was necessary for 1.x to 2.x to ensure that build systems treated them as separate artifacts because they existed in separate packages. Otherwise, a transitive dep on 2.x would have overridden 1.x and you'd get a bunch of Now, in 2.x to 3.x, the opposite is true. These exist in the same package and therefore should likely retain the same groupId because the behavior of the build system treating them as providing the same API in the same package is desired (modulo the inevitable-but-hopefully-rare |
Basically all libraries that internally depend on RxJava 2 functions that do not have their equivalent in RxJava 3 or vice versa.
That is true but it allows for mixing and matching libraries that depend on RxJava 2 and 3 in one application.
Currently it looks more like an evolution of RxJava 2, there are only few incompatible changes. As a creator of library I understand the need of dropping support for APIs that are inferior. The problem is that RxJava is wildly popular and not all libraries will get updated at once. There is gonna be a transition period — which has a potential to be a major pain (recently there was a similar case in React Native world related to gradle update — compile/api/implementation case). In which library maintainers would potentially need to support two versions. This could be relieved to a degree by adding binary compatible versions of functions to RxJava 2 and Question: What is the advantage of having |
The groupId for RxJava 2 had its major number added so the pattern is followed for 3. There is about 6 months until release. Libraries can start the adaptation right now by depending on the release candidates.
Again, which libraries are these? I'm sure I can help with making those libraries version agnostic. For example, the |
I think it is far better to eat the cost of the number staying the same in
maven coordinates. OkHttp just did this recently with good success
…On Thu, Aug 1, 2019, 11:37 AM David Karnok ***@***.***> wrote:
The groupId for RxJava 2 had its major number added so the pattern is
followed for 3.
There is about 6 months until release. Libraries can start the adaptation
right now by depending on the release candidates.
Basically all libraries that internally depend on
Again, which libraries are these? I'm sure I can help with making those
libraries version agnostic. For example, the defer(Callable) could be
implemented locally thus not depending on Rx' implementation.
TestSubscriber can be also localized with APIs as needed.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#6606?email_source=notifications&email_token=AAKMJPQN7KNOSABCD2JSNZ3QCL7KZA5CNFSM4IIIW5WKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD3K7VHA#issuecomment-517339804>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAKMJPUYI3LEHS7DB4ERIXDQCL7KZANCNFSM4IIIW5WA>
.
|
Exactly this move in case of a single dependency migration to RxJava 3 will make the compiler to complain if
I personally maintain https://github.com/Polidea/RxAndroidBle
As for this moment I do not have an idea how to do that using the APIs that RxJava 2 provides. Maybe a (pre)migration guide would help. Making the middle consumers (RxLib maintainers) to reimplement parts of RxJava to keep binary compatibility both ways is not ideal. It allows for more implementation errors where the same work could be added to another version of Technically whole RxJava could be reimplemented/shadowed internally by each library and only bridge signals at the very thin layer below its API. This would reduce the amount of friction on RxJava major bumps. This is along the lines of my second idea from the original post where we would have only a reactive interface ( (I may be drifting offtopic, sorry in that case) |
What about the following case? We release |
Even with a separate groupId that case can still happen. The JVM picks the first occurrence of duplicate classes on the classpath so in the current configuration when both 3.x and 2.x inevitably end up on the classpath it's a tossup based on tiny variants as to which is first. Thankfully if you're using the modulepath or Android your build just up and fails and you spend a chunk of time figuring out how to resolve this, not that the experience is dramatically better than getting a random version. For people depending on latest this is what they signed up for. I'm not sympathetic to the case that their app will break since that's a reflection on the choice to break binary compatibility, not their choice of a dynamic dependency. If they were concerned with this case they would have specified a range that kept the major version at 2. |
And in that first case, even with an explicit RxJava 3.x dependency, the classpath might have 2.x from a transitive dependency that winds up on the classpath first which means you'll run on 2.x at runtime. Both of the classpath cases are going to be extremely poor user experiences. |
This is to be expected when following Semantic Versioning pattern. I have a similar thoughts that JakeWharton stated above — using wildcard dependencies is an anti-pattern and asking for troubles on major version changes. The question evolves — what for we have a major version in Semantic Versioning? We could always create a new library (or publish under new groupId) if backwards compatibility is broken. |
From uber/AutoDispose#366 - a good example of the kinds of build system hoops users will have to jump through api 'io.reactivex.rxjava3:rxjava:3.0.0-RC1'
api 'io.reactivex.rxjava2:rxandroid:2.1.1'
api('com.uber.autodispose:autodispose-ktx:1.2.0') {
exclude group: 'io.reactivex.rxjava2'
exclude group: 'io.reactivex.rxjava2:rxandroid'
}
api('com.uber.autodispose:autodispose-android-ktx:1.2.0') {
exclude group: 'io.reactivex.rxjava2'
exclude group: 'io.reactivex.rxjava2:rxandroid'
}
api('com.uber.autodispose:autodispose-android-archcomponents-ktx:1.2.0') {
exclude group: 'io.reactivex.rxjava2'
exclude group: 'io.reactivex.rxjava2:rxandroid'
} |
@ZacSweers That wouldn't be much better if we had RxJava has to move forward and the least murky solution is to have it under a standalone id, founding a fresh set of dependent libraries. One end of it is libraries like RxAndroid that only needs to build and release under In Zac's case and this latter case, there is a question: why would your users switch to RxJava 3 so soon? How long would you have to support 2 versions? Why not follow RxJava 3 and feature freeze your RxJava 2 support? |
The breaking changes are not related to the groupId change and we need to stop conflating the two problems. The binary incompatibility is a problem no matter what groupId is chosen. You've offered:
And the underlying cause of Zac's issue is just that. However, what Zac was drawing attention to is the hoop-jumping now required in the build system to ensure that two copies of RxJava do not end up on the classpath. This is entirely unrelated to the binary incompatibility and would be required even if 3.x was 100% compatible with 2.x. The package name and the groupId are fundamentally linked. If one changes, the other should. If one does not change, the other should not. Either RxJava 3 should reside in |
After careful considerations of all target environments (Android/Desktop/Server) as well as any future major versions targeting Java 9+, I decided the path with the least problems will be having RxJava 3 reside in the new group id and in a new package entirely: Group ID: In addition, the base classes and interfaces (i.e., Since The other types won't be such lucky as |
I'm glad this is getting resolved, as of interop issues I have a proposal. Over a cup of coffee w/ @Tagakov we've figured a way to make v2 <-> v3 interop smoother.
I've used this techinique in past in the StorIO project where we had Caveats:
If this all looks good, I'm happy to make PRs to RxJava to make it happen. |
To add to that, we've also explored a path where v2 reactive types would extend v3 ones or vice versa with similar
|
The new package structure has been released with 3.0.0-RC2 and there is a support library so that v2 and v3 can talk to each other without hidden or overt compilation/runtime problems from before. |
Intro:
Since RxJava has a very compelling interface it is widely used as such. Some libraries also use it internally. RxJava 2 and 3 have some breaking changes but they both live in same packages.
Problem:
(I am not an expert in this field but here it goes)
Dependencies in Java are resolved by the full name (i.e. package + class name). Since the package name has not changed between RxJava 2 and 3 there are duplicate classes found during compilation. If two libraries (first level dependencies) have a dependency different major versions of RxJava (as a second level dependency to your app) they will not compile together.
Using
gradle
it is possible to make a first level dependency use a different second level dependency than it declares by using the below code inbuild.gradle
file:But then there is a good chance that some of those libraries will face binary incompatibilities introduced between RxJava 2 and 3.
This poses a potential logistics problem for the applications consuming RxJava based libraries. There is no way to ensure that those libs dependent on RxJava 2 and 3 will work together — the app developer would need to substitute libs that do not allow to be used with one a specific RxJava version or postpone migration. Developers would potentially need to wait until all their dependencies will migrate to RxJava 3 before they can switch. There is no way to create an interop between RxJava 2 and 3 like it was the case with RxJava 1 and 2.
Question:
Has this problem been considered?
Ideas:
2.3.x
. E.g.:Supplier<T>
,Observable/Single.defer(Supplier<T>)
but keepObservable/Single.defer(Callable<T>)
(mark it as@Deprecated
and point to the new function), etc.Observable.startWithItem(T)
but keepObservable.startWith(T)
This could make a usable subset of RxJava 2 binary compatible with RxJava 3 allowing it to easily swapped at a later point when adoption is high enough.
Observable
,Flowable
,Single
,Completable
and their.subcribe()
functions in the main package so they could be exposed as an API of all libraries that are ofRxLibrary
kind and the operator implementations in some extensions / other packages. This could make the usage more cumbersome in Java (but Kotlin language has extensions so this could be mitigated somewhat). This could make the Rx API more future-proofThis issue is a place for discussion (while somewhat related to #6524)
The text was updated successfully, but these errors were encountered: