Experimental Scala port

Discuss issues specific the Scala port of Box2D
Villane
Posts: 101
Joined: Mon Sep 01, 2008 6:32 am

Experimental Scala port

Postby Villane » Mon Sep 01, 2008 1:35 pm

Hi, everyone!

I just got working a preliminary version of a JBox2D 2.0.1 port to Scala. I still have lots of work to do before releasing anything though, and I'm not really sure yet if I want to turn this into a project that needs maintenance -- I primarily did it for my own game. And my port is with a twist:

* it's primarily focused on cleaner API's and code readability instead of speed and similarity to the C++/Java versions
(Actually without those goals I wouldn't have started it, because you can easily use JBox2D from Scala anyway)
* speed is still important, and I'm even thinking of writing a Scala compiler plugin that could optimize vector/matrix math behind the scenes, but that may be too crazy an idea. But currently I even "de-optimized" some of the math where it made code simpler.
* as much as possible is immutable. For example vectors, matrices, transforms are immutable
* operators are back (and more) compared to Java (well, in Scala operator and method are the same thing) -- for example cross products can be written like w2 × ccp.r2, since Scala allows special unicode characters in method names
* I know very little about physics, for me this is more of an exercise in API design and porting Java code to Scala

Due to many differences to the original code, I'm not sure how easy it is to keep this code current as Box2D is developed. But there is some hope because there is less code in the Scala version -- I haven't measured yet (as some code is yet to be ported), but I'm estimating that there is at least 2 times less lines of code than the Java version. Could be even less than that.

If anyone is interested to see the code, let me know. It still needs some more work and cleanup, though, so I won't be able to show it to you immediately.

BorisTheBrave
Posts: 1911
Joined: Mon Jan 07, 2008 10:51 am
Contact:

Re: Experimental Scala port

Postby BorisTheBrave » Mon Sep 01, 2008 4:03 pm

Sounds cool. I've never heard of a language that can do operator overloads like that, it's really just the thing for the cross product, and (I'm guessing) nigh-on useless for most other circumstances. I'm curious as to what else you did to clean up the API.

You have missed an important reason why the ports generally stick closely to the clunky C++ API: user support issues :| . Perhaps not a problem for you, as people can always use Java instead of Scala if they cannot figure out the differences.

ewjordan
Posts: 803
Joined: Sun Sep 23, 2007 2:35 pm

Re: Experimental Scala port

Postby ewjordan » Tue Sep 02, 2008 12:51 am

Awesome! I like Scala a lot and would be very interested in seeing the code when it's ready. When porting from C++ to Java, I found myself constantly longing for the type of stuff that is allowed in Scala, to the point that I almost considered doing that instead. Great to hear that you took it on! How is performance compared to the pure Java? I wonder if the immutability of Vec2s and Mat22s could allow for better JVM optimizations than we can get in the Java version...

Definitely put me on the list (my username at gmail) or post a note here when you've got something to show.

Also, depending on how much work it looks like it would be (can't say without seeing how many changes you've made to the structure and API), I'd be willing to consider supporting this alongside JBox2d if you decide you don't want to handle a whole project yourself.

@BorisTheBrave:
Sounds cool. I've never heard of a language that can do operator overloads like that, it's really just the thing for the cross product, and (I'm guessing) nigh-on useless for most other circumstances. I'm curious as to what else you did to clean up the API.

Just in case anyone had the thought "C++ has been able to do that for DECADES!" (as I did the first time I read that), notice that the overloaded expression was "w2 × ccp.r2", not "w2 * ccp.r2" - Scala lets you do use any unary operator in infix form, and generally speaking probably has the most flexible overloading scheme of any popular language right now. Dangerous stuff in the wrong hands, though that seems to be Scala's approach to everything... :)

Villane
Posts: 101
Joined: Mon Sep 01, 2008 6:32 am

Re: Experimental Scala port

Postby Villane » Tue Sep 02, 2008 1:06 am

Thanks for pointing out the user support angle, Boris. Indeed I hadn't thought of that. But I guess this port will most likely remain experimental anyway. I might use it for my game at first and switch to JBox2D later if I start missing new features or improvements.

I'm still not done with cleaning the API (and internals too), but most of what I've done or thinking about doing is:

* instead of filling objects passed in as parameters, return newly created objects (sometimes tuples)
* use Scala's Option[T] instead of null to indicate optional stuff (where it makes sense)
* replacing the small data holder classes with tuples and case classes (immutable if possible)
* making things private where possible (haven't looked much into it yet)
* no getters and setters -- Scala has uniform access for fields and methods. So i'm using only fields, but writing a Scala-style setter/getter where necessary (which are accessed the same way as the field)
* implicit conversions from tuples to vectors and matrices, extension methods for floats
these allow to write stuff like: body.linearVelocity = 0.5f * (1.0f, 2.0f), although they incur a small performance penalty
* replacing linked list where the list is kept in the items themselves with Scala collections (I haven't figured out the best ones to use yet). If this turns out to perform badly, I'm thinking of going back to the old behavior, but writing a generic DoublyLinkedListItem trait that can be mixed in to the classes that are in lists so you wouldn't have to reimplement the list functionality everywhere.
* replaced the custom hashtable with Scala's HashMap (will look into other options later)
* replaced the whole contact registers business with a simple pattern match (since it was pretty much hard coded anyway):

Code: Select all

    contact = (shape1, shape2) match {
      case (s1: Circle, s2: Circle) => CircleContact(s1, s2)
      case (s1: Polygon, s2: Circle) => PolygonCircleContact(s1, s2)
      case (s1: Polygon, s2: Polygon) => PolygonContact(s1, s2)
      ...
   }

* etc.

ewjordan, I can hopefully compare the performance sometime this week, as of now I still have some bugs that make current comparision pointless.

ewjordan
Posts: 803
Joined: Sun Sep 23, 2007 2:35 pm

Re: Experimental Scala port

Postby ewjordan » Tue Sep 02, 2008 9:47 am

Well, good luck with all of that, it should be very cool if it works out - that's pretty much a laundry list of all the reasons Scala is better than Java (and why I'm planning on migrating a lot of my development efforts to Scala ASAP). A lot of that stuff could theoretically improve performance by a huge factor if the JVM (or even the Scala compiler) takes proper advantage of the extra constraints imposed - I'll have to dig into the compiler source a bit to see if it's actually happening, of course, and I kind of doubt it is at this early stage, but I'm very excited about the possibility.

Re: making things private where possible, in JBox2d I haven't been as aggressive about that even as Erin has with Box2d, mainly because Java's package permissions just aren't as flexible as C++'s (there's no friend designation, for instance), so there's no way to expose things in different sub-packages to each other without just making them public, and in the engine there's a lot of that kind of access that needs to happen... :( I'm not sure if Scala has anything more fine grained that will help with that. Even so, there's a lot that I can make private that I haven't yet, and I'll probably put that on the list for the next update since one of the main complaints people have about JBox2d is that it feels too much like a C++ engine, and part of that is all the public members with Javadocs that say "Don't touch this, you could break stuff!."

Villane
Posts: 101
Joined: Mon Sep 01, 2008 6:32 am

Re: Experimental Scala port

Postby Villane » Tue Sep 02, 2008 3:11 pm

Actually, controlling visibility and packages in Scala is indeed more flexible (and sometimes more restrictive). I'm not familiar with all aspects of it, but I know you can define members as private[packagename] or protected[packagename] to make something visible in that package only. And packages truly nest in Scala, so box2d.dynamics.contacts is a member of box2d.dynamics. In Java they are separate packages.

I'm currently facing some strange issues: getting very different results in the pyramid test in SlickTestMain. The Scala version has the shapes falling slower, and the pyramid crumbles down. Perhaps it's just too slow or I have introduced some bugs. In any case, I probably have some days of bug hunting ahead :)
The Scala version is using less memory, though -- 26MB vs. 30MB, if I look at the memory usage of the process. Of course, this could be something else affecting it, but I think it might be due to the immutable classes -- the instances can be shared a lot -- for example I never create Vec2(0,0) but use a constant instead.

If I reduce the number of shapes to just the bottom row of the pyramid and they can fall asleep, I'm seeing ca 2150 FPS in Java and 1850 FPS in Scala. I'm not sure if this is the best indicator, though.

Villane
Posts: 101
Joined: Mon Sep 01, 2008 6:32 am

Re: Experimental Scala port

Postby Villane » Wed Sep 03, 2008 1:25 pm

I was getting depressed about the bad performance of the port, but after doing some more digging for issues, I managed to track down and eliminate quite a horrible performance blooper I made, and the kinds are easily made with Scala:
I was iterating over the list of bodies in World.solve, and it is implemented as an ArrayList currently. I used for-comprehension with filtering

Code: Select all

    for (seed <- bodyList
      if (((seed.flags & (BodyFlags.island | BodyFlags.sleep | BodyFlags.frozen)) == 0) && !seed.isStatic)
    ) {...}

This creates a filtered collection, and in this case it was doing something like resizing the arrays, or creating new ones or something like that. Moving that if statement to inside the loop made a huge difference in overall performance!

Code: Select all

    for (seed <- bodyList) {
     if (((seed.flags & (BodyFlags.island | BodyFlags.sleep | BodyFlags.frozen)) == 0) && !seed.isStatic) {
     ...
     }
   }

Actually, I should have thought of this earlier -- I have blogged about similar issues with Scala performance: http://villane.wordpress.com/2008/02/07 ... avs-while/

Anyway, now the application behaves more similarly to the Java port and is much faster (but still perhaps two times slower than JBox2D). Anyway, this gives me hope that the performance can be made to almost match the Java version.

Villane
Posts: 101
Joined: Mon Sep 01, 2008 6:32 am

Re: Experimental Scala port

Postby Villane » Sat Sep 06, 2008 9:38 am

After several evenings of profiling, I'm giving up for the moment on trying to bring the performance up to the JBox2D levels. I have tried little optimizations here and there, but nothing gives significant improvement without making code less readable.
At the moment the Scala port *seems* about 2 times slower than Java (in the pyramid test while bodies are not sleeping), but I can't say exactly before doing more precise measuring.

So I'm focusing on finishing the API changes and some code clean up, then I can make the code available.

Villane
Posts: 101
Joined: Mon Sep 01, 2008 6:32 am

Re: Experimental Scala port

Postby Villane » Sun Sep 07, 2008 1:13 pm

As another experiment, I wrote a parser (using the Scala parser combinators) for a JSON-like box2d world description format. It gets parsed into some wrapper classes containing BodyDefs, ShapeDefs and JointDefs. Simple worlds can be described like this:

Code: Select all

world {
  aabb: ((-200,-100),(200,200))
  gravity: (0,-10)
  bodies: [
    body {
      pos: (11.5, -5)
      shapes: [polygon{vertices: [(10,0),(5,5),(0,0)]}]
    }
    body {
      pos: (0,-10)
      shapes: [box { hx: 10, hy: 10 }]
    }
    body ball1 {
      pos: (0, 5)
      shapes: [circle{radius:3 density: 1}]
    }
    body ball2 {
      pos: (-5, 30)
      shapes: [circle{density: 1}]
    }
  ]
  joints: [
    distanceJoint {
      body1: ball1
      body2: ball2
      length: 15
    }
  ]
}

I'm not sure how useful this will turn out to be or how easy it would be to create parsers for this in other languages. It should be fairly similar to JSON parsing, but is strongly typed and requires types to be defined.

Actually I'm thinking of making the syntax more generic (so for a specific application you would only need to define the types) and calling it STON for Strongly Typed Object Notation :)

For even easier creation of complex scenes, it would probably be useful to introduce some math functions, variables and loops, but that would turn it into almost a programming language instead of a simple data format and I'm not sure I would even want to go there.

Villane
Posts: 101
Joined: Mon Sep 01, 2008 6:32 am

Re: Experimental Scala port

Postby Villane » Mon Sep 08, 2008 7:40 am

I have now implemented part of the test bed (integrating with Slick) and after looking at some of the on-screen measurements, it seems like the immutable Vector thing is turning out rather like I expected. During lots of activity, there may be more Vectors created than in the Java version (every operation creates a new vector plus I un-inlined some things during porting), but once things settle down then vector count becomes lower than Java (there's never a need for cloning vectors).

I have this crazy idea that it would be possible (and not insanely difficult) to write a plug-in for the Scala compiler that takes care of the inlining the vector operations, but this is beyond my current skills. I might give it a shot, though.


Return to “Scala”



Who is online

Users browsing this forum: No registered users and 2 guests