2

I am writing a small JavaFx application in Scala and I like to use RxScala and RxJavaFx for this. With the following code I get a RxJava Observable:

JavaFxObservable.fromObservableValue(textfield.textProperty())

Obviously, as I write in Scala, I would like to have a RxScala Observable instead. Now I found this post, saying that I either have to import the implicit conversion class JavaConversions._ or call toScalaObservable directly. However, the first option doesn't do it for me and the second option looks kind of ugly:

Option 1:

import rx.lang.scala.JavaConversions._
JavaFxObservable.fromObservableValue(textfield.textProperty())
  .map(s => /* do something */)

This doesn't work, as RxJava offers a map operator as well, although the type of the argument is technically speaking different.

Option 2:

import rx.lang.scala.JavaConversions._
toScalaObservable(JavaFxObservable.fromObservableValue(textfield.textProperty()))
  .map(s => /* do something */)

This works, but be honest people, this looks just really horrible!

Question 1: Am I missing something or are these really the only two options?

I mean, to convert from Java's standard collections to Scala's collections (and vise versa) you got two option: JavaConverters and JavaConversions. The former introduces a keyword asJava/asScala, whereas the latter is kind of equivalent to rx.lang.scala.JavaConversions and does the conversion for you implicitly (if you're lucky!). Googling on the preferences of these two, it is clear that most people prefer the more explicit implicit conversion from JavaConverters with the asScala keyword.

Question 2: Is there a similar construction like JavaConverters with RxScala? This would make the code above so much more cleaner, I would say:

import rx.lang.scala.JavaConverters._ // this class doesn't exist!
JavaFxObservable.fromObservableValue(textfield.textProperty())
  .asScala
  .map(s => /* do something */)
Community
  • 1
  • 1
RvanHeest
  • 869
  • 6
  • 12

3 Answers3

3

I'd write your example as follows:

import rx.lang.scala.JavaConversions._
val texts: Observable[String] = JavaFxObservable.fromObservableValue(textfield.textProperty())
texts.map(s => /* do something */)

where Observable[String] is the Scala Observable. Giving an explicit type for the val texts ensures that the implicit conversion kicks in.

Why no asScala?

This would require another implicit wrapper class (let's call in PreScalaObservable), with only one method called toScala, so that when you'd write myJavaObservable.toScala, the compiler would turn it into something like toPreScalaObservable(myJavaObservable).toScala.

Having two wrapper classes would be a bit confusing. Or if you're very smart, you could actually put the asScala method into the Scala Observable and implement it just as returning this, and since the Java Observable has no method called asScala, myJavaObservable.toScala would work. But again, this might be quite complex to grasp for beginners...

But if you have a better idea, or know how to present this simply, I encourage you to open an issue in the RxScala issues; the project is still in 0.x and nothing is set in stone... ;-)

Samuel Gruetter
  • 1,713
  • 12
  • 11
  • To be honest, I really like the chaining of all the operators. That's one of the defining powers of the Rx API (as it is with the Scala Collections API). Having to introduce extra `val`s including explicit typing isn't something I particularly like to do and see in Scala. It's a trick that works though, that's for certain! I will look into this some more and definitely consider moving this discussion the the RxScala issues. I assume I can do a pull request myself as well over there. Let's keep in tough on this! – RvanHeest Sep 16 '16 at 07:33
0

Why did you need to convert form RXJava to RXScala?, RXScala has all the same features that RXJava has. For example

ZIP:

  @Test def zip(): Unit = {
    addHeader("Observable zip")
    Observable.just("hello")
      .zip(Observable.just(" scala"))
      .zip(Observable.just(" world!"))
      .map(s => s._1._1.concat(s._1._2).concat(s._2).toUpperCase)
      .subscribe(s => println(s));
  }

MERGE:

  @Test def merge(): Unit = {
    addHeader("Observable merge")
    Observable.just("hello")
      .merge(Observable.just(" scala"))
      .merge(Observable.just(" world!"))
      .reduce((s, s1) => s.concat(s1))
      .map(s => s.toUpperCase).subscribe(s => println(s))
  }

FLATMAP:

  @Test def flatMap(): Unit = {
    addHeader("Flat Map")
    val text = "number mutated in flatMap::"
    val list = getList
    Observable.from(list)
      .flatMap(n => Observable.just(n) //--> New pipeline
        .map(n => text.concat(String.valueOf(n))))
      .map(s => s.toUpperCase())
      .subscribe(s => println(s))
  }

I would start from scratch to be honest with you. If you want to take a look of more operator examples https://github.com/politrons/reactiveScala

paul
  • 12,873
  • 23
  • 91
  • 153
  • I really don't understand what you mean! Are you arguing "*Why is there a RxScala if it has all the same features as RxJava?*"? My reason for asking how to convert between RxJava and RxScala is because Java's lambda expressions don't match with Scala's lambdas as of 2.11 and having a consistency in your code (use RxScala everywhere in your app) is also a nice thing. Maybe you could explain a bit more of what you wanted to say with "Why converting" and "starting from scratch". – RvanHeest Sep 23 '16 at 09:47
  • maybe I did not understand you, are you using JavaConverters because there´s no way to do with RXScala the same thing than JavaFxObservable?. I was suggesting that with RXScala you can do exactly the same than with RxJava so there´s no need to port any code from Java – paul Sep 23 '16 at 09:58
  • Ah, that's what you mean. Indeed in this case I came to this issue via RxJavaFx, which wraps JavaFx UI events in an `Observable` (which in itself is pretty useful!), but I was thinking of a general API that provides me with a RxJava `Observable`, which needs to be converted into a RxScala `Observable`. I fully acknowledge the fact that RxScala in itself is a wrapper for Scala around the RxJava library, but it has some stuff that works better with RxScala if you're writing in Scala. For example, the difference in lambda's that I mentioned before... – RvanHeest Sep 23 '16 at 11:30
0

This question was the starting point of this pull request on the RxScala project.

The syntax proposed in the original question can be used by importing rx.lang.scala.JavaConverters.

import rx.lang.scala.JavaConverters._
JavaFxObservable.fromObservableValue(textfield.textProperty())
  .asScala
  .map(s => /* do something */)

Likewise a Scala Observable can be transformed into a Java Observable using asJava.

See also the examples of intended use.

RvanHeest
  • 869
  • 6
  • 12