Java facades

In Design Patterns, Gamma et al describe a Facade as an "object that provides a single, simplified interface to the more general facilities of a subsystem". It is thus an ideal pattern to apply to the design of Java interfaces for Tcl, as it hides the complexity of the underlying Java sub-system, and provides Tcl scripts with flexible and disciplined access to instances of that sub-system.

In this example, we will create a simple facade to the GregorianCalendar class, that implements a timer with milli-second resolution. (Unlike Tcl's clock clicks command, this timer will always return milliseconds regardless of the system you are running on.) Here, without further fanfare, is the Java code for the facade (in the file tutorial/tcltk98/JTimer.java):

package tutorial.tcltk98;
import java.util.*;

public class JTimer {
  long startTime = 0;

  public void start () {
    GregorianCalendar cal = new GregorianCalendar();
    startTime = cal.getTime().getTime();
  }

  public String stop () {
    GregorianCalendar cal = new GregorianCalendar();
    long elapsedTime = cal.getTime().getTime() - startTime;
    return Long.toString(elapsedTime);
  }
}
This class has a single instance variable, startTime, and two methods, start and stop. Note that the class and method declarations are all public, so we can access them from Tcl Blend.
More about Java packages
The first two lines of this file deal with packages. The package statement must be the first line of code in a file. It says that this file is in the package tutorial.tcltk98 -- and it must of course be located in the directory tutorial/tcltk98/ relative to one of the entries in our CLASSPATH. The second says that we want to make all classes in the java.util package visible in this file. The only one we use explicitly here is GregorianCalendar, so we could also have written
  import java.util.GregorianCalendar;
Note that classes in java.lang, such as the java.util.Long class we use in stop(), are imported by default into every file.

The operation of this facade is fairly straight-forward. When we call the start method, it gets the current time by creating a new calendar object. It then gets a java.util.Date object using Calendar.getTime(), and from that Date object, gets the time in milliseconds (since sometime in 1970) using Date.getTime(). When it calls the stop method, it gets the time in milliseconds again, converts the difference to a String, and returns it.

This class is contained in the file JTimer.java in the directory tutorial/tcltk98/ (relative to your classpath). After compiling it, in wish type:

  set timer [java::new tutorial.tcltk98.JTimer]
  $timer start
Count to five, and then enter:
  $timer stop
Let's see if Tcl agrees with Java on this (this only works in wish):
  $t start; after 1000 {puts [$t stop]}
On my Windows NT machine, I get 1001 or 1002, which seems about right if we allow for some calling overhead.

Now, a word about Java types. The Java language specification defines the length of primitive data-types as follows:

Type Bits
char 8
short 16
int 32
long 64
That means that, unlike in C, an int is always 32 bits long, and a long is always 64 bits long. It makes no difference what machine I run on, a conforming Java implementation will provide these word lengths.

So how does Tcl Blend handle 64-bit words? Not very well! Try this:

  set currentTime [[java::new java.util.GregorianCalendar] getTime]
  $currentTime getTime 
For me, this printed "442684108." Depending on your luck, you might get a negative number -- regardless, it's wrong. Now try this:
  [$currentTime -noconvert getTime] toString
For me, this printed "902385816268."

Bogon alert
Tcl Blend does not convert Java longs properly. To avoid this problem, always be aware of methods that accept long arguments or return a long result, and do the conversion betweens longs and strings in Java. The JTimer shows an example of the latter; for the former, use the Long.valueOf() static method.