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

typesafe-core #319

Closed
wants to merge 8 commits into from
Closed

Conversation

mattrjacobs
Copy link
Contributor

Here's another attempt at making rx-core typesafe and still supporting dynamic languages. The previous attempt was #304. Enough changed (including the 0.10 release) since I submitted #304 that it made more sense to start fresh with this one. All the comments from that PR still apply, and the 'subscribe on map' issue is now handled.

This will make RxJava completely static by removing all Object overloads (see #208 and #204).


Implementation notes originally posted at #204 (comment):

After implementing and throwing away a few different approaches we have landed on a solution we feel will balance the various competing priorities.

Our goals are:

  • support static typing for Java/Scala/Kotlin etc by removing the Object overloads
  • support any JVM language, static or dynamically typed
  • allow all languages to use the same rx.Observable class so that we don't divide libraries with helpers such as GroovyObservable, ClojureObservable etc that then need to be converted back and forth when doing interop
  • do not require special classloaders or agents to enable runtime bytecode generation
  • do not remove static operators to enable proxying
  • small jars and limited or no dependencies

The solution we have arrived at will work as follows:

  • The rxjava-core source code will delete all Object overload methods and be pure static java.
    • Any language that supports functional interfaces directly (such as Java 8 and XTend) can use the Java core version directly.
  • Languages needing specific lambda/clojure type mapping to the Func_/Action_ types will have language specific Jars created via build-time bytecode generation.
    • Any method with a Func_/Action_ argument will be overloaded with a version supporting the language requirements.

For example:

The default Java version:

public static <T> Observable<T> filter(Observable<T> that, Func1<T, Boolean> predicate)

A Groovy version:

public static <T> Observable<T> filter(Observable<T> that, groovy.lang.Closure predicate)
  • A jar per language will be created as follows:
    • rxjava-x.y.z.jar
    • rxjava-groovy-x.y.z.jar
    • rxjava-clojure-x.y.z.jar
    • rxjava-scala-x.y.z.jar
    • rxjava-jruby-x.y.z.jar
    • rxjava-kotlin-x.y.z.jar

A project will include just the jar that meets their language needs, there will no longer be a "core" jar plus the language adaptor.

The drawback of this is that mixing two of these in a classpath will result in non-deterministic loading (whichever is loaded last wins) and that is the version that will be used. This means if a library depends on rxjava.jar but is using Groovy and needs rxjava-groovy.jar it is up to the developer of that project to make sure they have only the rxjava-groovy.jar version. This is not ideal but is a one-time pain setting up a build and is better than the constant pain of missing static typing or converting to/from different Observable implementations for different languages.

  • At this time we are optimizing for projects using a single language or Java + another language. If there are use cases where people are trying to mix multiple languages in a very polyglot manner we have two options:
    • include an rxjava-dynamic.jar version that re-adds the Object overloads
    • include build configs for common combinations of languages such as rxjava-groovy-clojure.jar
  • Language adaptations (such as clojure which has preferred idioms that necessitate wrapping) will still be possible through the language-adaptor projects and be included in the appropriate language jars.

This should not break any code but will require a slight change to the build dependencies in your project when we release this.

We hope that this enables the RxJava project to better achieve its goal of being polyglot and targeting the JVM in general and not any specific languages without sacrificing interop or idiomatic usage in each of the languages.

mattrjacobs and others added 7 commits August 12, 2013 23:07
Conflicts:
	rxjava-core/src/main/java/rx/Observable.java
	rxjava-core/src/main/java/rx/observables/BlockingObservable.java
	rxjava-core/src/main/java/rx/subjects/PublishSubject.java
 - Added license to files I touched and moved Gradle config around
 - Bugfix to codegeneration - explicitly call a static/instance method in body
 - Remove '? super' generic definitions
 -- I couldn't get these to work once we removed the Object overloads that was apparently being invoked instead of the staticly typed method so removing them.
If someone else can get these generics working then please submit a new pull request.
 - Removing zip FuncN overloads - they conflict with dynamic languages
 -- These methods will need different names as they have the same argument count so break with dynamic overloads once we do static handling of dynamic languages.
 - Upgrade to Gradle 1.6 (needed for Scala build to succeed)
 - s/rxjava-core-x.y.z.jar/rxjava-x.y.z.jar
 - Properly changed all artifacts of rxjava-core to be rxjava-x.y.z.*
 - For Groovy/Clojure/JRuby/dynamic, moved dependency on rxjava-core to provided scope, as well as all tests
 - For Scala, left rxjava-core as compile scope, since rxjava-scala jar doesn't contain Observable (as constructed)
 - Fixed classpaths for running example code in Clojure and Groovy
 - rxjava-scala Gradle jar task now includes rxjava-core classfiles
 - Leaving rxjava-swing UnitTest inner classes in the Jar (in case Scala consumes them)
 - Fix Maven artifactId for rxjava-core, so that dependencies can correctly build POMs (rxjava-swing in this case)
 - Shortened names of rxjava-scala implicit methods, per @jmhofer's suggestion
 * Broke apart monolithic code generator as well
 * Changed signature in core to subscribe(Map<String, Action>) for type-safety
 * Removed rxjava-dynamic module
…herwise conflict

 * 2 'buffer' methods introduced this case.
@cloudbees-pull-request-builder

RxJava-pull-requests #201 FAILURE
Looks like there's a problem with this pull request

}
}
} catch (Exception ex) {
System.out.println("Exception while creating body for dynamic version of : " + initialMethod.getName());
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this wrap-and-throw rather than printing and ignoring the exception?

@jmhofer
Copy link
Contributor

jmhofer commented Aug 20, 2013

When trying to build, I get "Could not find property 'ideaProject' on task set." (for :language-adaptors:rxjava-scala). What can I do against that?

@mattrjacobs
Copy link
Contributor Author

Are you building using gradle or gradlew? gradlew is a wrapper script at
the root of RxJava that allows for consistent builds (pins to gradle 1.6)

For more context on why this is a useful convention, see:
http://www.gradle.org/docs/current/userguide/gradle_wrapper.html

-Matt

On Tue, Aug 20, 2013 at 12:02 AM, Joachim Hofer notifications@github.comwrote:

When trying to build, I get "Could not find property 'ideaProject' on task
set." (for :language-adaptors:rxjava-scala). What can I do against that?


Reply to this email directly or view it on GitHubhttps://github.com//pull/319#issuecomment-22926217
.

@jmhofer
Copy link
Contributor

jmhofer commented Aug 20, 2013

Thanks, with gradlew it works. I simply didn't know about the wrapper script.

@cloudbees-pull-request-builder

RxJava-pull-requests #202 FAILURE
Looks like there's a problem with this pull request

@benjchristensen
Copy link
Member

Replacing with #323

jihoonson pushed a commit to jihoonson/RxJava that referenced this pull request Mar 6, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants