www.delorie.com/gnu/docs/kawa/kawa-tour_9.html   search  
 
Buy GNU books!


Kawa: Compiling Scheme to Java

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1.8 Procedures

Scheme has procedures as first-class values. Java does not. However, we can simulate procedure values, by overriding of virtual methods.

 
class Procedure {
  public abstract Object applyN (Object[] args);
  public abstract Object apply0 ();
  public abstract Object apply1 (Object arg1);
  ...;
  public abstract Object apply4 (Object arg1, ..., Object arg4);
  ...
}

We represent Scheme procedures using sub-classes of the abstract class Procedure. To call (apply) a procedure with no arguments, you invoke its apply0 method; to invoke a procedure, passing it a single argument, you use its apply1 method; and so on using apply4 if you have 4 arguments. Alternatively, you can bundle up all the arguments into an array, and use the applyN method. If you have more than 4 arguments, you have to use applyN.

Notice that all Procedure sub-classes have to implement all 6 methods, at least to the extent of throwing an exception if it is passed the wrong number of arguments. However, there are utility classes Procedure0 to Procedure4 and ProcedureN.

 
class Procedure1 extends Procedure {
  public abstract Object applyN (Object[] args)
  {
    if (args.length != 1)
      throw new WrongArguments();
    return apply1(args[0]);
  }
  public Object apply0 ()
   { throw new WrongArguments(); }
  public abstract Object apply1 (Object arg1);
  public Object apply2 (Object arg1, Object arg2)
  { throw new WrongArguments();}
  ...
}

Primitive procedures are generally written in Java as sub-classes of these helper classes. For example:

 
class cdr extends Procedure1 {
  public Object apply1 (Object arg1)
   { return ((Pair) arg1).cdr; }
}

A user-defined Scheme procedure is compiled to a class that is descended from Procedure. For example, a variable-argument procedure is implemented as a sub-class of ProcedureN, with an applyN method comprising the bytecode compiled from the Scheme procedure body. Thus primitive and user-defined procedure have the same calling convention.

If a nested procedure references a lexical variable in an outer procedure, the inner procedure is implemented by a "closure". Kawa implements a closure as a Procedure object with a "static link" field that points to the inherited environment. In that case the lexical variable must be heap allocated, but otherwise lexical variables use local Java variable slots. (This is conceptually similar to the "Inner classes" proposed for JDK 1.1.)

 
class ModuleBody extends Procedure0 {
  public Object apply0 ()
  {return run(Environment.current()); }
  public abstract Object run (Environment env);
  ...
}

Top-level forms (including top-level definitions) are treated as if they were nested inside a dummy procedure. A ModuleBody is such a dummy procedure. When a file is loaded, the result is a ModuleBody; invoking run causes the top-level actions to be executed.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

  webmaster   donations   bookstore     delorie software   privacy  
  Copyright © 2003   by The Free Software Foundation     Updated Jun 2003