Monday, August 6, 2012

processing.js porting gotchas

I've been porting entries from my Java Advent Calendars (both the 2009 and 2011 editions) into HTML5, via the wonder that is Processing.js. The original Processing (a Java based IDE and API, geared at students and artists) is amazing enough -- I really credit it with enabling me to make some really fun stuff in folks' browsers (not to mention effortlessly generated native Windows and Mac apps) but it feels like applets are kind of on their way out. So Processing.js allowing what is basically straight Java code to be run as Javascript (using the Canvas object) is super amazing. I don't know what black magic preprocessing they do to get 90% of my Java classes to work in a Javascript context, but it's great work, and less problematic than I thought.

Still, there are lots of gotchas, so here's my list of things to look out for, as determined by my personal experience. (Which involved some Processing code against the older version of Java that didn't use typed collections, and might not be using the latest and greatest release of Processing.js.)

Environment Gotchas

  • Speed. Some of my code that runs fine as an applet runs a bit slow in the browser, or at least with  some browsers javascript engines. I haven't yet isolated what operations slow things the most, but it seems like the line drawing isn't as quick.
  • Error messages. When you're coding up new stuff, the error messages can be a bit opaque, and generally don't have the line number of the original .pjs file. 
  • Chrome and running things locally. Chrome tends to balk at running code loaded locally from the file system. (Might be a good excuse for that Python webserver trick I mentioned earlier.)
  • 3Dness. One of my first attempts at porting a simple 3D app ended in failure, I haven't researched if there's an easy way around this.
Coding Gotchas
Most of the coding problems I've run into involve collections.
  • Collections & Inheritance. I had a big problem with this early-on, with an overly ambitious engine project I was doing for the Boston HTML5 Gamejam. It used a lot of object subclassing, and it seems like items in a heterogeneous collection of subclasses weren't being cast to quite the right types when it came time to call function names that they had in common.
  • The .removeAll() function for Collections is late to the party. I'm not sure if later version of the library fix this, but it was a known issue.
  • HashSet is not implemented. I liked to use HashSets for collections where order didn't matter but I wanted to be able to remove specific member items efficiently. ArrayList is a pretty good substitute.
  • In the bad old days of Java, before it's implementation of "foreach", you had to use iterators, and the best way to remove an item if you were in the loop itself was through the Iterator.remove() method (which removes it from the container the iterator is based off of.) .remove on the Processing.js iterator doesn't seem to propagate up to the main collection. (Combined with the .removeAll() lack, this was a little annoying.)
  • Apparently in Processing,
    ArrayList<SomeClass>things = new ArrayList<SomeClass>();
    is fine, but Processing.js gets confused, and wants spaces before the collection name. (For a while this led be to be unfairly pessimistic about the porting from Java, because the error message wasn't clear, and I was writing lines like that without spaces all over the place.)
So despite this list, in practice I've been increasingly impressed with what Processing.js can do. It's an awesome set of training wheels for people looking to go from Java to Javascript, and sometimes I wonder if it might not be a solid tool in its own right, as crazily ambitious as "run Java classes in Javascript" seems.

Followup: one other class of error involve java being strict about its types, but js being loose:

 int spotToYcoord(int s){
     return s / 3;
This returns int values only in Java, but the equivalent of floats in javascript. (In this case the fix was to explicitly return floor(s/3) instead.

1 comment:

  1. That's cool. The only port I've tried so far turned out to be pretty trivial - it's just that I felt I was working blind most of the time in terms of not knowing what the problem was and not knowing what alternative approach might work around it.
    (linking the Java version since I haven't decided how to showcase Javascript stuff)

    And only a few simple changes needed - mostly the iterator stuff you mention.