Scripting with DynamicJava

> DynamicJava is a JavaTM interpreter which try to follow the Java Language Specification. Some extensions have been added to ease the creation of small programs. All these extensions have been added with the same goal in mind: reduce the amount of code to write and make it easy to translate a script to a valid Java program. The following sections describe these extensions.

> ## Top-level

> A Java program (called a compilation unit in the specification) can contain:
> - An optional `package` clause,
> - Optionals `import` clauses,
> - One or more `class` or `interface` declarations.
> A DynamicJava script is a Java program. It can also contain statements, expressions and function declarations. The meaning of a `package` clause is different. Here is an example (top_level.djava):

>     System.out.println("Example script");

>     // Place the script in the package p.
>     package p;

>     public class C {
>         public C() {
>     	System.out.println("C created");
>         }
>     }

>     // Place the script in the anonymous package.
>     package;
>     import p.*;

>     // Create an instance of p.C
>     new C();

> The `package` and `import` clauses can be placed anywhere at the top-level in a script. The `package` clause used without package name places the script in the anonymous package (the package where the application was launched).

> ## Variables

> In scripts declaring variables is optional. The interpreter automatically declares a variable when an unknown identifier is encountered on the left side of an assignment. A variable declared by the interpreter has no difference with an explicitly declared one: the interpreter assigns a type to the variable (the type of the right hand side of the assignment) and this type will be enforced later in the program. This means that it is not possible to dynamically modify the type of a variable.
> Note: The variable declared in an expression like `var = null;` is a `java.lang.Object`.

> ## Functions

> The syntax used to declare a method can be used to declare a function in the top level environment. The resulting function can be used everywhere in the top-level environment and in the body of every functions. Functions are not visible from classes, can be recursive and can be overloaded, exactly like JavaTM methods.
> Here is an example that use functions (functions.djava):

>     import java.math.*;

>     // A first version of the factorial function that
>     // takes an int as parameter
>     BigInteger fact(int n) {
>         // A forward reference to fact(BigInteger n)
>         return fact(new BigInteger("" + n));
>     }

>     // An overloaded recursive version of the factorial
>     // function that takes a BigInteger as parameter
>     BigInteger fact(BigInteger n) {
>         return (n.equals(BigInteger.ZERO)) ?
>             BigInteger.ONE : n.multiply(fact(n.subtract(BigInteger.ONE)));
>     }

>     System.out.println("fact(30) = " + fact(30));

> The body of a function can contain forward references to classes and to other functions. In fact the body of a function is lazily interpreted and the type checking is made the first time the function is called. So every class and function declared before the first invocation of a function can be used in its body.

> As mentioned above, the function declaration syntax is exactly the same as the method declaration syntax. This means that modifiers (`public`, `final`, `synchronized`, ...) and `throws` clause can be used. It is allowed to ease the transition from functions to methods but it is ignored by the interpreter.

> ## Classes

> The class declaration has exactly the same semantic in JavaTM and in DynamicJava programs with one exception: the top-level anonymous classes. The choice has been made to export the final variables declared in the top-level environment to these classes.

> ## Casts

> Some runtime casts are optional. The following example is a script that contains casts (casts1.djava):

>     i = 1;
>     byte   b1 = (byte)(i + 1);
>     Object o  = new Byte(b1);
>     Byte   b2 = (Byte)o;
>     Number n  = (Number)o;
>     b1 = ((Byte)o).byteValue();

> The next example is the same script without the optional runtime casts (casts2.djava):

>     i = 1;
>     byte   b1 = (byte)(i + 1);
>     Object o  = new Byte(b1);
>     Byte   b2 = o;
>     Number n  = o;
>     b1 = ((Byte)o).byteValue();

> The cast at the last line cannot be removed because the interpreter needs the information it holds to find the `byteValue` method while it makes the type checking of the expression.

Send comments, suggestions and bug reports to shillion@ilog.fr
Last modified: Mon Nov 22 10:58:37 MET 1999