I recently returned from
JavaOne 2005 in San
Francisco. The show was impressive for a number of reasons. The attendance
seemed to be about 30% larger than last year's. The same could be said for
the number of tutorials, sessions and BOFs. For example, there were enough
BOFs to run until 11:00pm at night. Many of the sessions were filled to
capacity, with over 600 attendees each technical presentation.
Given my strong background in C++, I am used
to a more amorphous attitude toward languages. Therefore, I was surprised to
see that there still is a vibrancy to Java that I do not see with C++.
Among the many interesting things that I saw,
two stand out: Eclipse and the scripting language called Groovy. I already
have
written about Eclipse, so here I simply note that Eclipse now seems to
dominate the Java IDE world. Groovy, on the other hand, is new. It prompted
me to look at Python-like scripting languages that run in a Java
environment.
In this article, I discuss
Jython and
Groovy, two
scripting languages that use the Java runtime environment. By the way,
JavaScript has nothing to do with the Java language, so it is not considered
here.
Jython
Jython is an interpret
uilt-in entities, Jython produces Java
compatible structures that it passes back and forth to the JVM. The code
below uses the Jython interactive shell, in which Jython takes the Python
built-in list structure and converts it to a Java list structure that is
then passed to the Java println function that then passes the result to the
JVM.
>>> print ['a','list','of','strings']
['a', 'list', 'of', 'strings']
>>>
Here is a simple program that uses the Java
Swing library to produce a trivial GUI application:
"""\
A simple demonstration of creating a swing tree widget from a
Python dictionary.
"""
import java
import javax
from pawt import swing
from pawt import awt
sampleData = {
'PyObject': {
'PyInteger':None,
'PyFloat':None,
'PyComplex':None,
'PySequence': {
'PyArray':None,
'PyList':None,
'PyTuple':None,
'PyString':None,
},
'PyClass': {
'PyJavaClass':None,
},
},
'sys':None,
'Py':None,
'PyException':None,
'__builtin__':None,
'ThreadState':None,
}
Node = swing.tree.DefaultMutableTreeNode
def addNode(tree, key, value):
node = Node(key)
tree.add(node)
if value is not None:
addLeaves(node, value.items())
def addLeaves(node, items):
items.sort()
for key, value in items:
addNode(node, key, value)
def makeTree(name, data):
tree = Node("Sample Tree")
addLeaves(tree, data.items())
return swing.JTree(tree)
def exit(e):
java.lang.System.exit(0)
if __name__ == '__main__':
tree = makeTree('Some JPython Classes', sampleData)
button = swing.JButton('Close Me!', actionPerformed=exit)
f = swing.JFrame("GridBag Layout Example");
p = swing.JFrame.getContentPane(f)
gb = awt.GridBagLayout()
p.setLayout(gb)
c = awt.GridBagConstraints();
c.weightx = 1.0;
c.fill = awt.GridBagConstraints.BOTH;
gb.setConstraints(tree, c);
c.gridx = 0;
c.gridy = awt.GridBagConstraints.RELATIVE;
gb.setConstraints(button, c);
p.add(tree)
p.add(button)
f.pack();
f.setSize(f.getPreferredSize());
f.show();
Jython has two main advantages. First, the
language is Python and has all of its strengths, including clean and
consistent syntax, introspection, dynamic creation of classes, properties
and attributes. Second, it runs at the speed of the JVM. On the other hand,
Jython also has two chief weakness. First is its need to convert constantly
between Python and Java structures. Second, Jython has not received much
work in recent years. That is about to change, however; the current
maintainer, Brian Zimmer, recently received three grants to continue work on
Jython.
The bottom line is if you know Python, then
you know Jython. The big gain is ready access to libraries such as Swing,
awt and so on.
er for the Python language. It is written in
Java to run under the Java VM. To handle Python b
Groovy
Groovy is a new language based on features
from Ruby, Python and Haskell. However, its runtime environment is any JVM.
The language syntax attempts to be Java-like, while making the form of the
language much simpler. Groovy is a statically typed language, so it requires
a compile step before producing Java byte code. Groovy does not currently
have an interpreter, although it does have a shell.
Groovy documentation offers an impressive
list of features:
- Closure support
- Native syntax for Lists and Maps
- Groovy Markup
- Groovy Path expression language
- Groovlets for implementing Servlets
easily in simple Groovy scripts
- Groovy SQL for making SQL more Groovy
- Groovy Beans for simpler syntax for
working with beans
- Groovy Template Engines which are
pluggable, simple to use, integrate GPath and compile to bytecode
- Ant scripting
- Regex syntax for neater scripting with
regular expressions
- Operator Overloading to simplify working
with datatypes Collections and Maps
- Polymorphic iteration and autoboxing
- Compiles straight to Java bytecode
- Works cleanly with all existing Java
objects and libraries
An interesting feature of Groovy is found its
definition and use of closure:
A closure in Groovy is an anonymous chunk
of code surrounded by braces that takes zero, one or more arguments,
returns a value, and can reference and use variables declared in its
surrounding lexical scope (i.e., the scope at its definition point). A
closure is like an anonymous inner class in Java. It is often used in
the same way. However, Groovy closures are more powerful and often more
convenient to specify and use.
Groovy's uses Java's standard types for
things such as dictionaries and lists. This means no translation is needed
between Groovy code and the JVM. This may improve execution time, depending
on the application.
Closures and Anonymous
Classes
Groovy's documentation provides an example
that illustrates the benefits of using closures in place of anonymous
classes. Using an anonymous class, we can write:
Button b = new Button ("Push Me");
b.onClick (new Action() {
public void execute (Object target)
{
buttonClicked();
}
});
</programlisting>
<para>
Using a closure, this becomes:
</para>
<programlisting>
Button b = new Button ("Push Me");
b.onClick { buttonClicked() }
Another nice feature of Groovy is its "each
operator, which is used to iterate over a collection:
SomeCollection stuff = new SomeCollection();
stuff.each() someClosure
// for example:
def myList = [1,2,4,5,6]
myList.each { println it } // where 'it' is current collection item
// outputs:
1
2
3
4
5
6
Groovy also has built-in structured
"builders" for languages such as XML, HTML and more. Again, a simple example
illustrates how natural it is to build structured text:
xml = new groovy.xml.MarkupBuilder()
def myList = ['acct1':['id':123111, 'type':'savings', 'balance':1234.56],
'acct2':['id':221212, 'type':'checking', 'balance':2010.02]]
doc = xml.accounts() {
for (entry in myList)
acct(id:entry.key) {
for (thing in entry.value)
item(name:thing.key, type=thing.value)
}
}
This small code fragment outputs:
<accounts>
<acct id='acct2'>
<item name='type'>checking</item>
<item name='id'>221212</item>
<item name='balance'>2010.02</item>
</acct>
<acct id='acct1'>
<item name='type'>savings</item>
<item name='id'>123111</item>
<item name='balance'>1234.56</item>
</acct>
Contrasting Jython and
Groovy
Bindings
In the following example, the use of variable
c is caught at compile time in a statically defined language. Only when a is
greater than b is the use of the undefined variable, c, detected in an
interpreted language.
a = 1
b = 2
if a > b:
print c
print a,b
Another major difference between a compiled
language and an interpreted one is when things are bound to their
references. In Groovy, the following code prints "Bound to local variable":
def varA = "Bound to global variable"
def closure = { varA }
public class C {
def varA = "Bound to local variable"
def closure = { varA } // bound to local varA at definition time
public def f = closure // f bound to local closure
};
def c = new C(); // create instance of C using new
println c.f() // invoke f in C
in Jython, the equivalent-looking code prints
"Bound to global variable":
varA = "Bound to global variable"
closure = lambda: varA
class C:
varA = "Bound to local variable"
closure = lambda self: varA
f = closure
c = C()
print c.f()
For those wanting more flexibility, the
Jython/Python bindings are handier. For those wanting more stability, the
Groovy implementation may be more desirable.
Currying
Currying function arguments is another
difference. Groovy has a special "curry" mechanism to bind arguments to a
function. In the following example, "foo bar" is printed:
def c = { arg1, arg2-> println "${arg1} ${arg2}" }
def d = c.curry("foo")
d("bar")
Jython inherits Python's natural ability to
curry arguments using a number of techniques. One is:
def c(arg1, arg2): print arg1,arg2
def d(arg2): c("foo",arg2)
d("bar")
Maturity
Jython has been around a long time and is
based on a mature language, Python. However, its development has stalled in
recent years. Groovy is a relatively new language and thus still is
developing. For example, its error diagnostics leave a lot to be desired.
Also, at the moment, Groovy's following is much smaller than Jython's or
Python's. However, both languages are picking up development activity, so
you have a chance to influence both languages if you want to become
involved.