After reading Steve Yegge’s Code’s Worst Enemy post I finally decided to give Rhino a whirl. I heard it mentioned here and there for a while now – mostly by Steve actually, but also by others. Actually others were mostly saying something among the lines “WTF is this Rhino shit Steve is talking about?”.
In fact a while ago I went to check it out. I saw the homepage and my thought process went something like this:
- oh, mozilla – this must be cool
- lol rhino picture
- it does what with Javascript?
- Javascript? With Java? WTF?
- allright, fuck it – I don’t have time for this crap right now
Now I went back, and decided this might be one of the most awesome things I have seen lately. To make the long story short, Rhino lets you write Javascript scripts that can leverage the Java API and will run on the JVM.
But isn’t Javascript, for making AJAX websites? Yes it is, but it is also a very nice scripting language. It has most of the nifty dynamic features of dynamic languages such as Ruby and Python (like ducktyping for example) and a familiar Java like syntax with braces, semicolons and etc. What can Rhino do for you?
First, it provides you with an interactive shell that uses Javascript syntax. I know that BeanShell gives you a similar functionality, but Rhino let’s you tap into Javascript specific language features and structures which are not present in BeanShell (at least as far as I know).
Second, it gives you a compiler you can use to turn your rhino js scripts into class files. So you can easily knock out bunch of scripts, compile them, and then stick them in your Java project and no one will ever know. Furthermore your Javascript code will benefit from JIT compilation and other VM goodies.
Finally, rhino lets you load a javascript at runtime, interpret it and return the result from within your Java code. Java 6 actually ships with the Rhino interpreter you can invoke at will.
But the overwhelming benefit here is that you get to code in Javascript. In other words, you get a language that is less verbose, more flexible and more dynamic than Java, which can do everything that Java does, and which integrates seamlessly with your Java code. Just read Steve’s post and you will see the point just as I did. Java verbosity does impair readability of code and Rhino is the solution and the cure.
To drive the point home, let’s do a “Hello World” example. First, in Java:
public class Hello
{
public static void main(String[] args)
{
System.out.println("Hello World!");
}
}
Have you ever tried teaching Java? You show people this example, and first thing you say is this:
“Don’t worry about the public class thing. We will talk about classes later, for now just keep in mind that this line has to be there. Consider it a standard boilerplate code.”
Then you do even more hand waving, telling people not to worry about static, or the String[] args bit and etc… Of course we, advanced programmer peoples know what this stuff means. But think about it – how much fucking code do you need to write just to run few simple tests.
Now let’s do the same thing Javascript under Rhino:
print("Hello World!");
The effect is exactly the same, but simplicity and readability of the code is incomparably better. What we are talking about here is a drastic reduction in the amount of the boilerplate code you need to write. You can also skip variable declarations, generics, casting and etc. So not only is your code becoming easier to read, but also easier and faster to write. This is just a silly example. You can do much more, for example check out this little gem taken directly out of the Rhino documentation:
t = java.lang.Thread(function () { print("Hi There!"); });
t.start()
I just extended the Thread class, implemented it’s run method, instantiated it and launched a thread in mere two lines. You can’t do this in Java! This is the kind of dynamic programming we are talking about. Actually, I don’t think you can do something like that in BeanShell either I might be wrong. Even if I am, Rhino outperforms BeanShell considerably in many cases.
Note that I can use the compiler that ships with Rhino to compile any of the scripts above into a .class file just as I would with an ordinary Java file. How to do this? Firs let’s talk about getting rhino set up. On my Ubuntu box I can install rhino simply by doing:
sudo aptitude install rhino
This will put a a wrapper for the interactive shell as an executable script under /usr/bin/rhino as well as the rhino jar file in /usr/share/java/js.jar. You may want to manually add this last path to your $CLASSPATH variable. This was not done for me upon installation, but then again I’m using dapper repositories so your millage may vary. If you are just planning to use the shell, this is all you will need to do.
Let’s say we named our hello world script hello.js. To run it using the rhino shell just do:
rhino hello.js
Yes, you have to explicitly call rhino. The #! thing doesn’t work – I tried it. One of my professors used to call this a “sheebang” but that reminds me of that stupid Ricky Martin song which makes it distinctively un-geeky in my mind. So I refuse to use that term. Instead I shall refer to it as “Octothrope – Exclamation Mark Junction” or something like that. I suspect it doesn’t work because /usr/bin/rhino is just a shell script that runs the shell from js.jar – not a true shell or interpreter in itself.
Unfortunately the package author didn’t provide a similar script wrapper for the compiler so you have to run it manually by evoking the appropriate method from js.jar. If you added the js.jar to your classpath, then it’s easy. The following command should generate hello.class file for you:
java org.mozilla.javascript.tools.jsc.Main hello.js
I recommend creating a wrapper script containing that line and sticking it somewhere in your path for quick access in the future. You can look at the /usr/bin/rhino scrip, and then just add the appropriate class name to it.
Once you compile your js file, you should be able to run it just like any other java class with one small caveat – it now depends on js.jar so you may need to package and ship it with your code and always include it in classpath.
On windows you will need to do everything manually since all you really get in the downloadable package from Mozilla is the jar file. Thus you will need to create the wrappers yourself. For example you can do something like this for the shell:
@java -classpath ".;C:\path\to\js.jar" org.mozilla.javascript.tools.shell.Main %1
Call it rhino.cmd or something. Then do this for the compiler:
@java -classpath ".;C:\path\to\js.jar" org.mozilla.javascript.tools.jsc.Main %1
Then just remember to include js.jar in your classpath, or put it in the environment variable.
What would you use this for? Tons of things. For example – unit tests. You can still use JUnit and shit, but now instead of a hundred lines you can set everything up in 30. Actually any kind of testing could be done with rhino. That and quick prototyping, and mock-ups. You really can code faster and think clearer when you don’t have to worry about all that boilerplate code. And hey, Steve is rewriting his whole MMO in Rhino – he thinks this is actually a better language for large projects than Java. And that’s good enough endorsement for me.
Now if I could just figure out how to make Eclipse to do that “compile as you type” shit for rhino scripts I would be a happy man. I bet there is a plugin that does this somewhere – I just need to find it. :)
[tags]rhino, java, mozilla, mozilla rhino, javascript, programming, steve yegge[/tags]
IBM uses rhino under the hood for the monitoring of unix machines in the IBM Tivoli monitoring 5.x product. Imho this is a great thing, apart from the bloated JVM ;). You write simple JS and can use all of the Java API.
Found this on google and just wanted to mention that the hash bang (shebang) works if you set it up right:
#!/usr/bin/env rhino
Thanks for the tip Kelly!
Also, whenever someone says “shebang” all I can think of is that stupid Ricky Martin song. :P
Pingback: Rhino - Scripting Java with Javascript [ Terminally Incoherent ]
Luke,
Love the Rhino. Spread the word.
I use Rhino quite a bit for testing, and it’s a wonderful fit. We use it as the core of our unit testing engine: http://www.thefrontside.net/crosscheck
Also, for all of those who get frustrated at the atrocious rhino shell, I suggest using JLine: http://www.thefrontside.net/blog/taming_the_rhino
Thanks for the tip Charles! I will definitely check it out!
Pingback: Yet Another JavaScript Blog » Leveraging the Java Servlet API with Rhino