Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to translate the Mario example from Elm to either pure JavaFX or to JavaFX+RxJava while preserving the high level abstraction of Elm?

I've recently seen this interesting presentation about reactive programming in Elm.

This made me wonder whether the language constructs used to implement the Mario game (in the shown presentation, and also in the picture below) can be mapped to similar high level language constructs either in pure JavaFX or in JavaFX combined with RxJava ?

In other words, would it be possible to express the Mario game implemented in Elm using the same conceptual abstractions (i.e. time dependent values) in either JavaFX alone or in JavaFX+RxJava ?

So if an experienced 1) JavaFX programmer or an experienced 2) JavaFX+RxJava+Functional programmer wants to port the Mario game from Elm to either 1) JavaFX or to 2) JavaFX+RxJava then which programmer could accomplish this task by using similar high-level abstractions as was used in Elm ?

The abstractions I have in mind for JavaFX are bindings and for JavaFX+RxJava are bindings+Observables/Subjects/Subscription.

enter image description here

like image 664
jhegedus Avatar asked Apr 01 '14 19:04

jhegedus


2 Answers

I say it is possible, without actually doing it :-)

This is only a guess as I have little experience in this field and none at all with Elm.

I think you will get closest to Elm by creating a ScalaFX wrapper for ReactFX, though you could probably also use Java 8 lambdas in combination with ReactFX rather than Scala. You will likely have to implement quite a few extensions to ReactFX as well as various other facilities to get the abstractions and elegance you desire.

Checkout Deprecating the Observer Pattern if you have not already done so. I think that it is quite relevant to this topic especially with regards to thinking about a reactive programming model as opposed to an observable model (which is what JavaFX ChangeListeners are). That said, I think if you use libraries such as ReactFX which are built upon the JavaFX property and listener frameworks, then you likely end up with the higher level abstraction of event streams that are useful for reactive programming.

Sure, you could make a Mario game in JavaFX without using ReactFX, but the code would be quite different and you would be working at a different level abstraction to that which you would be using with ReactFX. So pure JavaFX, without ReactFX would be less Elm like.

For a network layer, akka could be used to provide a reactive framework for multi-player games, this would allow you to use reactive programming top to bottom, both in your UI and in your communications system.

For the Sprite animations in the Mario sample, adopt the netopyr code for Creating a Sprite Animation with JavaFX.

For the physics calculations you could use the JBox2D library. You would need to create some kind of reactive wrapper around JBox2D to make it aware of stuff like JavaFX properties and ReactFX event streams and subscriptions. For the simplistic Mario sample, use of an external library would probably be more trouble than its worth. Instead you could use a basic home grown physics model (e.g. something like this ball animation experiment) and hook it into your reactive framework.

I advise getting in touch with Tomas Mikula, who has created ReactFX, and asking him your reactive programming for JavaFX questions. Robert Ladstätter has also done some cool stuff with ScalaFX and might be able to give you some further advice, though I don't know if he's worked with Reactive programming at all. I'd also suggest pinging the ScalaFX users forums, but I see you've already done that :-)

The Elm Mario sample is pretty simple, so I advise trying the translation to ReactFX yourself. Then I think the answer to your question will become self-evident. Now that I've written this => if you don't actually implement it and publish your solution as the correct answer, I might have to hunt you down and you wouldn't want that :-)

like image 38
jewelsea Avatar answered Oct 08 '22 03:10

jewelsea


I had a quick look at Elm and it is quite impressive (and expressive).

In Elm you construct your scene as

Signal Element

which in JavaFX would be roughly equivalent to

ObservableValue<Node>

Naive translation to JavaFX would mean that you swap the whole scene on each update, which is prohibitively costly. In Elm, Element is an immutable abstract representation of a scene node, constructed off the screen (off the DOM). It is cheap enough to recreate the whole scene graph on every update (because of immutability, it is safe to reuse unchanged branches). The root Element is rendered to DOM, but, as I understand it, only the first time the full DOM is constructed. On subsequent updates, Elm runtime runs an algorithm to compare the new root element to the old one and only modifies those parts of the DOM that need updating, which is fast enough. The same technique is used by React.js. So both Elm and React.js provide high-level functional abstraction, but use mutability under the covers for performance reasons.

With some additional syntactic noise, you can translate most Elm constructs to JavaFX (*). For example,

lift2 display Window.dimensions gameState

is equivalent to

import static org.fxmisc.EasyBind.*;

combine(Window.dimensions, gameState, display)

The missing piece is the library of immutable abstract widget representations and their efficient rendering into JavaFX scene graph.

What you could do is:

  • create such a widget library for JavaFX;
  • or even compile Elm to JavaFX (instead of HTML+JavaScript).

I would love to see either of those done.


(*) I think Elm records are very powerful and would require a lot of boilerplate in Java (or Scala).

Elm:

type Point = { x:Float, y:Float }

p = { 0.0, 0.0 }
q = { p | x <- 5.0 }

Java:

class Point {
    public final float x;
    public final float y;

    public Point(float x, float y) {
        this.x = x;
        this.y = y;
    }

    public Point updateX(float x) {
        return new Point(x, y);
    }

    public Point updateY(float y) {
        return new Point(x, y);
    }
}

Point p = new Point(0.0, 0.0);
Point q = p.updateX(5.0);

Scala:

case class Point(x: Float, y: Float)

val p = Point(0.0, 0.0)
val q = p.copy(x = 5.0f)
like image 167
Tomas Mikula Avatar answered Oct 08 '22 04:10

Tomas Mikula