| www.delorie.com/gnu/docs/kawa/kawa-tour_9.html | search |
![]() Buy GNU books! | |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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 |