Kawa, the Java-based Scheme system

Node:Loading Java functions into Scheme, Next:Evaluating Scheme expressions from Java, Previous:Low-level Field operations, Up:Low-level functions

### Loading Java functions into Scheme

When `kawa -C` compiles (see Files compilation) a Scheme module it creates a class that implements the `java.lang.Runnable` interface. (Usually it is a class that extends the `gnu.expr.ModuleBody`.) It is actually fairly easy to write similar "modules" by hand in Java, which is useful when you want to extend Kawa with new "primitive functions" written in Java. For each function you need to create an object that extends `gnu.mapping.Procedure`, and then bind it in the global environment. We will look at these two operations.

There are multiple ways you can create a `Procedure` object. Below is a simple example, using the `Procedure1` class, which is class extending `Procedure` that can be useful for one-argument procedure. You can use other classes to write procedures. For example a `ProcedureN` takes a variable number of arguments, and you must define `applyN(Object[] args)` method instead of `apply1`. (You may notice that some builtin classes extend `CpsProcedure`. Doing so allows has certain advantages, including support for full tail-recursion, but it has some costs, and is a bit trickier.)

         import gnu.mapping.*;
         import gnu.math.*;
         public class MyFunc extends Procedure1
         {
           // An "argument" that is part of each procedure instance.
           private Object arg0;

           public MyFunc(String name, Object arg0)
           {
             super(name);
             this.arg0 = arg0;
           }

           public Object apply1 (Object arg1)
           {
             // Here you can so whatever you want. In this example,
             // we return a pair of the argument and arg0.
             return gnu.lists.Pair.make(arg0, arg1);
           }
         }

You can create a `MyFunc` instance and call it from Java:

           Procedure myfunc1 = new MyFunc("my-func-1", Boolean.FALSE);
           Object aresult = myfunc1.apply1(some_object);

The name `my-func-1` is used when `myfunc1` is printed or when `myfunc1.toString()` is called. However, the Scheme variable `my-func-1` is still not bound. To define the function to Scheme, we can create a "module", which is a class intended to be loaded into the top-level environment. The provides the definitions to be loaded, as well as any actions to be performed on loading

         public class MyModule
         {
           // Define a function instance.
           public static final MyFunc myfunc1
             = new MyFunc("my-func-1", IntNum.make(1));
         }

If you use Scheme you can use `require`:

         #|kawa:1|# (require <MyModule>)
         #|kawa:2|# (my-func-1 0)
         (1 0)

Note that `require` magically defines `my-func-1` without you telling it to. For each public final field, the name and value of the field are entered in the top-level environment when the class is loaded. (If there are non-static fields, or the class implements `Runnable`, then an instance of the object is created, if one isn't available.) If the field value is a `Procedure` (or implements `Named`), then the name bound to the procedure is used instead of the field name. That is why the variable that gets bound in the Scheme environment is `my-func-1`, not `myfunc1`.

Instead of `(require <MyModule>)`, you can do `(load "MyModule")` or `(load "MyModule.class")`. If you're not using Scheme, you can use Kawa's `-f` option:

         $ kawa -f MyModule --xquery --
         #|kawa:1|# my-func-1(3+4)
         <list>1 7</list>

If you need to do some more complex calculations when a module is loaded, you can put them in a `run` method, and have the module implement `Runnable`:

         public class MyModule implements Runnable
         {
           public void run ()
           {
             Interpreter interp = Interpreter.getInterpreter();
             Object arg = Boolean.TRUE;
             interp.defineFunction (new MyFunc ("my-func-t", arg));
             System.err.println("MyModule loaded");
           }
         }

Loading `MyModule` causes `"MyModule loaded"` to be printed, and `my-func-t` to be defined. Using `Interpreter`'s `defineFunction` method is recommended because it does the righ things even for languages like Common Lisp that use separate "namespaces" for variables and functions.

A final trick is that you can have a `Procedure` be its own module:

         import gnu.mapping.*;
         import gnu.math.*;
         public class MyFunc2 extends Procedure2
         {
           public MyFunc(String name)
           {
             super(name);
           }

           public Object apply2 (Object arg1, arg2)
           {
             return gnu.lists.Pair.make(arg1, arg2);
           }

           public static final MyFunc myfunc1 = new MyFunc("my-func-2);
         }