-
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
Added java6 project using retrolambda #3764
Conversation
I don't think it's worth it. RxJava 2.x will be Java 6 based and the Stream-API interoperation has to go into a separate project; or just use somebody else's Stream -> Publisher wrapper. |
Vote for closing as unnecessary. RxJava 2.x targets Java 6 and we can live with the small inconvenience of using inner classes. |
@akarnokd @artem-zinnatullin: I'm not sure if it is only for convenience. Wouldn't there be a performance improvement by being able to use invoke dynamic internally? @rdegnan: Would it publish the jvm version in the classifier part of the artifact (rxjava-2.0.0-java8.jar)? |
Most or probably all use cases for Such usage of (Afaik) // Will try to invite some engineers with better knowledge of JVM/JDK to discussion. |
Internally, we have many context-capturing inner classes so I think lambdas would end up as object instances anyway and the runtime JIT is mostly capable of inlining through regular inner classes. |
@akarnokd could you try running your JMH test suite with java6 and java8? |
We can set it up to use classifiers, that would be better — right now it’s just appending ‘-java6’ to the name. In addition to removing thousands of lines of Java boilerplate, I think there are advantages to having a build that targets Java 8 in addition to a build that targets Java 6 via retrolambda. One problem is that methods like BlockingObservable.forEach are inconvenient to use in Java 8 because BlockingObservable also inherits forEach(java.util.function.Consumer) from Iterable, so using a lambda is not possible because it is ambiguous whether it should implement java.util.function.Consumer or io.reactivex.functions.Consumer. In the Java 8 build io.reactivex.functions.Consumer extends java.util.function.Consumer so this is not an issue. In addition we would be able to take advantage of things like default methods on io.reactivex.functions.* which can make functional programming in Java a lot more convenient (see https://github.com/javaslang/javaslang https://github.com/javaslang/javaslang). I’m also curious about the performance improvement in practice, though I’m not sure which perf test would best reflect the difference.
|
Those sound like binary incompatible features between the hypothetical On Wed, Mar 23, 2016, 7:44 PM Ryland Degnan notifications@github.com
|
Sorry, I don't have the capacity to experiment with various runtime versions right now. Most inner classes get instantiated during the assembly time thus you'd only see differences with trivial functions on short sequences. In addition, 2.x started out as a native Java 8 code and I didn't really need any Java 8 features inside the operators. It was more of a convenience in unit tests but Eclipse can turn a lambda into an inner class in a JDK 6 targeted project most of the time.
|
@JakeWharton the purpose of this is to have a single source code that generates 2 different artifacts. Android users would (by default) get the java6 compatible version. For those who want to use the java8 version they could change the dependency to point to java8 classifier. @akarnokd you want to close this PR without looking at performance metrics? |
@stealthcode but how other libraries will depend on RxJava then if we will have 2 artifacts…? |
Right. The artifacts need to be binary compatible for libraries to work On Wed, Mar 23, 2016, 8:06 PM Artem Zinnatullin notifications@github.com
|
@artem-zinnatullin here is a gradle example of how dependencies would be expressed. Java6 Project build.gradle compile 'io.reactivex:rxjava:1.1.2' // java 1.6 compatible Java8 Project build.gradle compile 'io.reactivex:rxjava:1.1.2:jdk18' // java 1.8 compatible
// alternate
compile group: 'io.reactivex', name: 'rxjava', version: '1.1.2', classifier: 'jdk18' |
@JakeWharton if a library depends on the RxJava java8 version then it's runtime should be 1.8 and thus all usages of that library should also be running on 1.8. Why would a library need to be binary compatible with both versions? |
@stealthcode please clarify if end user project will be able to specify which RxJava artifact it'll need: jdk8 or jdk6 even if some library that it depends on needs artifact with another Example:
|
@artem-zinnatullin in that situation the build would include both artifacts on the classpath and However if you can predict that all users of your library specifies |
Retrofit needs to be compatible with both because it works on both Android On Wed, Mar 23, 2016, 9:03 PM Aaron Tull notifications@github.com wrote:
|
You actually are actively making things worse by using the same package On Wed, Mar 23, 2016, 9:12 PM Jake Wharton jakewharton@gmail.com wrote:
|
Another option which would avoid having to use classifiers is to build rxandroid as a subproject alongside rxjava. As I have done here, it would compile the same sourceset plus the additional code that currently lives in the rxandroid repo, targeting java 6. RxAndroid would have no dependency on RxJava, the artifacts would be different and there is no reason people would want both. We would also know instantly if any changes to RxJava break android.
|
Except, again, the libraries that support both. You've basically just pushed the problem and burden of making two versions of every library or having two integrations on the hundreds of libraries that want to support both. This isn't acceptable. |
@stealthcode then it I'll basically kill development of generic libraries around RxJava that target both java 6 and java 6+ like Whole community will be confused and everybody will blame us for such decision. I'm sorry, but I'm voting against splitting library into two artifacts. |
I'm not an expert on how and when lambdas are converted to instances, but I'd expect whenever a lambda ends up in a field, it has to be instantiated. I did a search for "new Function" and they are only in the base classes mostly part of the convenience overloads: Flowable:
Functions Observable Single
Besides, I remember the time when we had all sorts of subprojects and changing some Java bits ended up breaking the compilation or tests of the other subprojects with no one around to help fix those. It is already cumbersome to keep track the features and tests in both 1.x and 2.x and I don't want to do more maintenance than necessary. I also agree with @JakeWharton and @artem-zinnatullin. |
I've recently read about The main advantage of targeting java 8 (i.e. ByteCode v52) is the ability to use the Note that I agree with @JakeWharton that if we decide to have to artifacts, the binary compatibility MUST be respected (and tested). Otherwise, multiple transitive dependencies may cause I think that if the build tool is properly setup, it shouldn't cause any problem to anyone. Worst case would be, having two transitive dependencies on RxJava 2, one jdk6 and one jdk8, depending on the classpath order, the jvm would either load the jdk6 bytecode (and not benefit from indy) or load jdk8 bytecode (and benefit from indy). |
The artifacts would be based on the same source code. I don't think that you could get a
If |
I strongly feel that there should be a single artifact. With Java 9 (which is not that far off) we can then use multi-version JARs to target Java 9+ enhancements on top of the Java 6+ base (such as adding support for all the Java 8+ and 9+ APIs). As for the performance improvements lambdas can offer, I'm pretty certain that if we have code where the perf benefits from a lambda, we can stop using anonymous inner classes and define static inner classes, or use static functions instead and get the same improvements. If we are "newing" up an Object such as a |
Thanks for the contribution. Since the decision has been made to go for Java 6, I don't see any need or value doing Java 8 sources and cross-compiling it. Certainly, some unit tests would love the simplified lambda syntax but the IDEs can usually fix the "syntax error" of a lambda expression. Java 9 is a bit far out and until the usual tools get updated, I can't comment on how the multi-versioned jars would work (out). What I definitely want is separate id for the 2.x. Let's discuss that further in #3170 |
Since #3668 was merged we should now be able to build a separate artifact for Java 6, while continuing to maintain the main project using Java 8. This splits the project into 'rxjava' and 'rxjava-java6', which compiles the same source code using retrolambda, and uses the animalsniffer plugin to ensure that we are not inadvertently using APIs introduced after Java 6.