Most programs contain a multitude of methods, spread across a large number of classes. Of course, it's difficult, if not impossible, to test all of these methods from just the main entry point of a program.
That's why unit tests are useful. Many programmers and software designers (including myself) stress the usefulness of unit tests in writing robust software. But a potential tradeoff occurs if you want to be able to access the various elements of your program in a more interactive manner.
When this is the case, it can quickly become cumbersome to write, compile, and run new unit tests for each result. I find this especially true when I don't know in advance how my program will behave given certain inputs (as can be the case in an AI program, for instance).
So, what to do?
To draw an analogy, consider the differences between programming in a language that is typically compiled (like Java or C++) and one that is more often interpreted (Python or Scheme).
Every write/test/debug cycle in the compiled language necessarily involves this extra step of compilation, which can be a tedious experience, especially for a load of small changes. This would lead us to conclude that interpreted languages are more fluid, and thus more easily modified. (There is a price for this flexibility: interpreted languages tend to perform less static checking over the code, such as type checking.)
Just as sometimes we might want to make a change to a program without having to go through the trouble of recompilation, we may also want to check some element of our program without the formality of adding a new unit test to our suite. When this is the case, it can help to have what is traditionally known as a "read-eval-print-loop" (or repl).
A repl is a text-based tool that takes an expression as input, evaluates it in the context of a certain program, and displays the result. It then waits to take another expression as input and repeats these operations. Such tools have their roots in Lisp-like languages, but they are also used in newer languages like Python.
The benefits of repl in Java programming
Languages such as these are not the only ones for which such a tool is useful. Java programmers can also benefit from using a repl, in ways other than just debugging.
When putting together a GUI, there are a lot of components that need to be laid out and connected. You can bet on the following when constructing GUIs:
- The components will interact with each other in non-obvious ways.
- It can be quite time-consuming to write out all the code for a GUI before ever running it.
- Inevitably, you'll want to change several aspects of the GUI once you see how it is physically displayed.
A common "solution" to this problem is the use of graphical GUI-building tools, such as those included in JBuilder, Forte, and other IDEs. Personally, I hate this approach -- it's difficult to know what Java code the tool is going to generate for you and you can't modify the generated code without the risk of losing compatibility with the GUI-building tool (in fact, some IDEs forcibly prevent you from modifying parts of the machine-generated code).
Also, many of these GUI-building tools use proprietary GUI libraries when generating Java code, limiting the compatibility of your GUIs.
I find that building GUIs is much easier with the use of a repl. I can simply define each GUI component interactively, and display it in turn. I can fix anything I don't like immediately. Then I can take interactions and paste them into my program.
One of the biggest advantages of programming in the Java language is the enormous wealth of APIs available for interfacing with everything from databases to Web services to televisions. But learning the semantics of an API takes time.
Often, the Javadocs won't nail down every aspect of the behavior of the API. The answer to this quandry is to test the API directly, and this can be done much more quickly with a repl -- just type in a method call and see the result!
A fringe benefit is that using a repl to test an API also reinforces a major behavior of most programmers -- that we tend to learn best by doing
Repls available for Java programming
So, if repls have so many advantages, the next obvious question is what repls are available for the Java language?
Jython (formerly known as JPython) is an implementation of Python (including a repl) in the Java programming language (certified 100% Pure). It actually compiles Python to (somewhat baroque) Java source code or directly to bytecode.
In the spirit of Python, every attempt was made to offer seamless Java interoperability with Jython. It gives you access to all of the Java standard libraries just as if you were programming natively in the language, as well as use of the existing Java class files. So you can use the repl to play not only with the standard libraries, but with your own Java (or Jython) classes that you've compiled to bytecode.
One significant consideration when using the Jython repl is that you are writing Python expressions, not Java expressions. The plus side of this is that you get the conciseness and beautiful syntactic sugar of Python.
For example, say I want to construct a new hash table that maps a to 1, b to 2, and c to 3. All I need to write in Jython is this:
>>> h = {'a':1, 'b':2, 'c':3}
|
The interpreter displays >>> before each new input line.
Jython syntax is also quite advantageous when exploring new GUI designs. For one thing, the various fields of a GUI element can be specified as keyword arguments to the constructor, like so:
>>> from javax.swing import * >>> f = JFrame(visible=1) |
This example illustrates some other differences between Jython and the Java language:
- Import statements have a very different syntax.
- ints are used instead of booleans (1 is true, 0 is false).
Here's another example where the Jython code saves you some typing -- adding action listeners to GUI elements. Normally, such listeners are specified as instances of anonymous inner classes using the Command Pattern. In Python (and many other "scripting" languages), such commands can be specified more succinctly using interactive function definitions. For example, let's build on the above interactive session and add a simple action listener to a JButton:
>>> def listener(event): ... print 'thank you' >>> |
This is an example of a function definition in Jython. The interpreter lets us know when it expects a statement to be continued on the next line by printing ellipses for the caret. This function takes a single argument and prints "thank you" to standard out. We can use it as an action listener as follows:
>>> panel = JPanel()
>>> panel.add(JButton('press me', actionPerformed=listener))
>>> f.getContentPane().add(panel)
>>> f.pack()
|
Now we'll have a window displayed on the screen with a button labeled "press me" that, when pressed, will print "thank you" to standard out. Imagine how much more wordy this would be using Java code.
Of course, there are disadvantages. For example:
- You lose static type checking (although static checking is arguably of little value in a repl).
- Because the expressions you type in the repl are not Java code, you can't copy-and-paste expressions from the repl into your program without first translating them.
- When using Jython with Java code, you have the added intellectual burden of juggling two languages in your head simultaneously (although some people consider that fun).
Another Java-usable repl is DynamicJava, a true Java-based (well, that's almost right) open-source tool with a few differences:
- The repl language lets you get away without specifying the static types of variables when you declare them.
- You don't have to add a semicolon at the end of a statement. The interpreter also (sloppily) returns
nullas the result of evaluating a statement. (It would have been better if statements didn't return values at all.)
- You are not restricted from accessing the private fields of objects from within the repl.
For beginning Java programmers, these differences can be significant because they can cause confusion. More experienced programmers will probably welcome some of the relaxed restrictions. In either case, DynamicJava is a robust and very useful software product (and it helps that it's free).
This installment hopefully has identified and demonstrated a major tool to let you interactively evaluate expressions and statements in Java programs without getting bogged down in recompilation -- the "read-eval-print-loop" or repl. We have also demonstrated how repls are important when building GUIs or when you simply want to quickly examine the wealth of Java APIs that are available to you.
-
Jython 2.1 is an implementation of the high-level, dynamic, object-oriented Python that allows you to run Python on any Java platform. (Discover more on the progenitor language, Python 2.2.)
- This installment of the Charming Python column on the
developerWorks Linux zone, "Inside JPython and Python for .NET," offers a peek inside JPython.
- Also check out DynamicJava, a Java source interpreter.
- Don't forget to download DrJava and take advantage of the power of an IDE with a built-in repl.
- Read all of Eric Allen's
Diagnosing Java Code
columns.
- Find more Java resources on the
developerWorks Java technology zone.
Eric Allen has a bachelor's degree in computer science and mathematics from Cornell University and is a PhD candidate in the Java programming languages team at Rice University. Before returning to Rice to finish his degree, Eric was the lead Java software developer at Cycorp, Inc. He has also moderated the Java Beginner discussion forum at JavaWorld. His research concerns the development of semantic models and static analysis tools for the Java language, both at the source and bytecode levels. Eric is the lead developer of Rice's experimental compiler for the NextGen programming language, an extension of the Java language with added language features, and is a project manager of DrJava, an open-source Java IDE designed for beginners. Contact Eric at eallen@cs.rice.edu.
Comments (Undergoing maintenance)





