We begin with a customary example: the `Hello World!' as a JiST program, listed in Figure 2. The first thing to note is that this is a valid Java program.
You can compile it with a Java compiler:
And, run it as a regular Java program:
Scanning the source listing, you should also notice the repeated use of the JistAPI, on lines 3, 14 and 17. This JistAPI class represents the application interface exposed by the simulation kernel. Of course, if we run our hello program without the JiST runtime, simply under a regular Java runtime, there will be no active simulation kernel. In this case, the entire JistAPI acts as a dummy class that merely facilitates type-safe execution: the Entity interface is empty, the sleep call does nothing and the getTime function returns zero. In fact, the correct way to think about the JistAPI is that it marks the program source in a manner that both respects Java syntax and is preserved through the compilation process. It allows type-safe compilation of JiST simulation programs using a conventional Java compiler.
However, we can also run our hello simulation under JiST:
In this case, we will have a simulation kernel loaded and running. Among other things, this kernel installs a class loader into the JVM, which dynamically rewrites our hello bytecode as it is loaded. The various JistAPI markings within the compiled simulation program serve to direct the code transformations that introduce the simulation time semantics into the bytecode. The entire JiST functionality is exposed to the simulation developer in this manner, via jist.runtime.JistAPI.
Although it is possible to silently modify the meaning of some existing functions, such as Thread.sleep and System.currentTimeMillis instead of introducing new JistAPI functions, we decided against this kind of syntactic sugar. First, not all simulation time primitives have Java counterparts and we would like to keep all the simulation-oriented functions together. Second, our approach makes simulation-oriented primitives explicit, and preserves the existing functionality.
Now, returning to our hello example, you will notice that the call
to myEvent on line 15 is recursive. Running the
program on its own, without the JiST runtime, will produce a stack overflow, as
expected, on exactly that line. However, executing the same application under
JiST produces the output:
> simulation start | |||
> hello world, t=1 | |||
> hello world, t=2 | |||
> etc. | |||
In essence, our method call has been transformed into a simulation event on the hello entity. It is scheduled and invoked by the simulation kernel in simulation time. Note, also, that hello is an entity, not a regular object, since it implements the JistAPI.Entity interface. You may also observe, from the output, that the sleep serves to advance the simulation time of the system. And, clearly, there is no stack overflow. Thus, although we reuse the Java language, as well as its compiler and virtual machine, we extend the object model of the language and execution semantics of the virtual machine, so that simulation programs will run in simulation time.