JRuby, still the fastest Ruby implementation
A fairly comprehensive benchmark test has been run across all available (and even some pending) Ruby implementations.
JRuby continues to be the fastest 1.8 compatible implementation by quite a long way.
Converting Java developers
I’m the resident “JRuby guy” most everywhere I go. Coupling a lack of Ruby-loving attendees and my predilection to get into “conversations” about the relative merits of various programming environments, the title all to often fits. Guilty as charged your honor. So, tonight I was asked an interesting question:
How do you convince a Java developer to use Ruby?
My answer:
You don’t.
My second answer:
You wait until the person is unhappy with what they have and then you be there as a resource to them when they go looking for a better solution.
Basically, the long version of “it depends”. The particular instance I was being asked about was a fairly large team (30) using Spring MVC. They all knew Java of course and one senior member of the team was trying to convince the team lead (also at the meeting) that JRuby or an equivalent would be a good way forward. This team lead was pretty skeptical, (surprisingly so given my previous interactions with him), and wanted to know what this extra layer of abstraction was buying him. I replied that it vary well may not buy him anything. I think this was an answer he definitely did not expect and I also think it was exactly the “right” answer.
I went on to elaborate on my “it depends” answer, probing to find out where their bottlenecks were. Was it hardware, delivery time, team size? The first answer was performance, “it has to run fast” he said. Some more back and forth and it seemed performance was important but not constraining in the way it would be on a single desktop or an embedded device. No, this was a web app, and he eventually conceded that three new developers is probably a lot more expensive than three more servers. I brought up the fact that they were using Spring instead of just straight Servlets. Why? That’s potentially a ton of layers of logic to go through. Clearly there was a value to the tradeoff and my point was soon made. After about 15 minutes of questions from the team lead he seemed quite satisfied and stated that he felt much better about the prospect of moving to something like JRuby now after talking to me. He even said that he would like me to come speak to his team and field their questions about JRuby.
This was not the first time this has happened to me and I hope it won’t be the last.
So, my takeaway for all Ruby advocates:
- The hard sell of Rails may have worked to get lots of attention for Rails/Ruby and for that I thank everyone who helped make Rails a success, but it won’t pull everyone across.
- After 2+ years of hype, hype, hype, a realistic explanation of what Ruby can and can’t do, what it is good and not so good for is a welcome thing to many skeptics.
- Even the doubtful can be converted if given the proper care and attention. Be passionate, be sincere and be honest and that will come across with far more weight than your expose on how higher order functions are the solution to all of programming’s ills.
- JRuby is the magic bullet that makes a lot of people even capible of conemplating a migration over to Ruby-land. It integrates with Java flawlessley and it’s the fastest Ruby available so that helps a whole lot for the peformance-minded crowd.
What Ruby developers really want
What’s your biggest beef with Ruby today? A need for a better thought out sandbox model, people conflating Ruby and Rails (my personal vote), or some other issue? For 50% of Ruby Inside readers it appears to be performance. This is interesting because it’s one of the easiest things that can be remedied RIGHT NOW. Yup, just switch to JRuby and (barring some native extension problems) you’re up and running and faster. Sometimes this performance boost is quite significant as the JRuby team regularly demonstrates in their blog posts. So what are you waiting for, go grab the fastest Ruby available and start enjoying that performance!
Gemini dev update #2
So much has changed since my last update. First off, we’ve created a system for managers to be plugged into the basic game state. The three core managers are game object, update and render. The default versions of these three get auto-added to a game state unless you specify your own to use.
Why might this be useful or interesting you ask? Well consider the problem of one behavior we were working on. CollidableWhenMoving hooks into a game object’s move method using on_after_move. The behavior then needs to check the object that just moved against anything it might have collided with. There’s a basic behavior (BoundingBoxCollidable) that does the actual coordinate checking, but CollidableWhenMoving still needs to get a list of other game objects to check against. Previously, the behavior was keeping an internal list of objects it had been added to. This sort of worked, except that it used class level variables which really breaks down if you want to be able to pause, swap to another state for a while and then come back. Also, other collision’ish behaviors would have to maintain their own lists of game objects and there was no way to share those lists so CollidableWhenMoving could only collide with other CollidableWhenMoving objects. Oh, and it was also an ugly hack.
So the answer was clear, we needed a way for behaviors to generically get information. This evolved into the idea of a state having some number of managers that could provide that information. So now after the movement of a game object, CollidableWhenMoving can query the GameObjectManager registered on the state and ask it for an appropriate list of objects to check against.
Another big improvement was the idea that behaviors should be able to be used as interfaces. So kind_of? was enhanced to check against behaviors as well. Also a new behavior class method: depends_on_kind_of was added to allow a behavior to express the need for another behavior witout having to specify the type. Unlike depends_on, the depends_on_kind_of method does not require or add any dependant behaviors, it simply sets up a instantiation check that will raise an exception if there is not a sub-class of the declared behavior on the object. This allows you to depend on some kind of algorithm object, even though you don’t care which one.
The keymap concept has been enhanced to give you some fairly nice syntax for setting up input processing. Here’s the keymap file for the example pong-like game.
map KEY_HELD, :source_value => Input::KEY_Q, :destination_type => :p1_paddle_movement, :destination_value => :up map KEY_HELD, :source_value => Input::KEY_A, :destination_type => :p1_paddle_movement, :destination_value => :down map KEY_HELD, :source_value => Input::KEY_O, :destination_type => :p2_paddle_movement, :destination_value => :up map KEY_HELD, :source_value => Input::KEY_L, :destination_type => :p2_paddle_movement, :destination_value => :down
The destination_type and destination_value are totally arbitrary and should be customized to make sense for each particular game. Other supported input map types are key_pressed, key_released, mouse_moved and mouse_button_pressed/released.
Finally, we’ve split out the example game into the examples directory. It’s now an actual game with animating sprites, scores and two player controls.
50% performance boost, for free?
Wouldn’t it be nice to live in a world where you can wake up one day and have some project of yours just magically run 50% faster? Well my friends, JRuby is a world of mystery and amazement. In the past few days the JRuby team has been working feverishly on their Java integration rewrite. Along the way Charles Nutter managed to clean up the number of layers a Ruby call had to go through to get to Java. The net result: my test case for Gemini that I posted about earlier when from a frame rate of 27 fps to 40 fps. None of my actual code changed, I just swapped out the jruby.jar for a newer build. Swapping them back takes me back down to the 27 fps range. So, mana does fall from heaven occasionally, at least in JRuby land.
Java game library + JRuby + awesome DSL = Gemini
I’ve been working with JRuby to build high level systems on top of powerful Java libraries for about 2 years now. My most successful endeavor has been Monkeybars, a libarary for making Swing a lot easier to use. My other project has been in the game development arena. The project name is Gemini, and although it’s not nearly as advanced as Monkeybars, I was able to get to a significant point over the weekend. Yes, here in all its glory, the simple “crapton of sprites bouncing back and forth demo”.
Now you’re probably saying, big deal, I can do that in like 40 lines of code in <insert favorite programming language/framework> and no doubt you would be correct. What’s interesting about the way Gemini does things is in how it gives you an extremely flexible way of compositing together your game objects and your application as a whole.
The code to get this going using Gemini is pretty straightforward. We have a game state that is loaded by Gemini when it starts up. That game state then instantiates 1000 of our game objects and they proceed to load their images and care for their own logic of bouncing around on the screen.
Here’s the code in main.rb that kicks off the app:
require 'gemini' Gemini::Main.new("Test game", 640, 480)
And here is the state that is loaded by default when Gemini runs: main_state.rb
class MainState < Gemini::BaseState def load @sprites = [] 1000.times {@sprites << Duke.new} end def update(delta) @sprites.each { |sprite| sprite.update(delta) } end def render(graphics) @sprites.each { |sprite| sprite.draw } end end [/sourcecode] Finally we have the Duke class that was instantiated in the MainGame class: [sourcecode lang='ruby'] class Duke < Gemini::GameObject has_behavior :Movable2D has_behavior :Sprite has_behavior :UpdatesAtConsistantRate def load self.image = "duke.png" self.updates_per_second = 30 @direction = :right self.x = rand(640 - image.width) self.y = rand(480 - image.height) end def tick if x > (640 – image.width) || x < 0 @direction = @direction == :right ? :left : :right end self.x = x + (@direction == :right ? 1 : -1) end end [/sourcecode] Apart from some hackish ternary ifs in the Duke class I think the whole thing is pretty darn readable, especially considering all that it is doing. As you can see, everything is extremely declarative including those has_behavior calls in the Duke class. Those nifty bits of metaprogramming bring in all the crunchy goodness of the class and make the x, y, image and updates_per_second methods appear. Movable2D gives us a move method and also pulls in the Positional2D behavior that provides the x and y methods. UpdatesAtConsistantRate gives us an update method that calls tick at the rate specified by updates_per_second. Finally the Sprite behavior gives us the image method and the draw method that gets called in the MainGame class. Most of this is bare bones at the moment. What if you don't have the UpdatesAtConsistantRate? When update is called you asplode. Same for Sprite / render. So clearly a more flexible game state is needed, probably involving the game object behaviors auto-registering themselves with the game state to be called during an update/render cycle. But as a whole I'm quite happy with the way Gemini is starting to shape up. Next on the agenda is getting keyboard mapping hooked into the RecievesKeyboardEvents behavior so you can control duke, then we'll have what could pass for a real game.