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


Kawa, the Java-based Scheme system

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

10.8.3 How a module becomes a class

If you want to just use a Scheme module as a module (i.e. load or require it), you don't care how it gets translated into a module class. However, Kawa gives you some control over how this is done, and you can use a Scheme module to define a class which you can use with other Java classes. This style of class definition is an alternative to define-class [not yet implemented] which lets you define classes and instances fairly conveniently.

The default name of the module class is the main part of the filename of the Scheme source file (with directories and extensions sripped off). That can be overridden by the -T Kawa command-line flag. The package-prefix specified by the -P flag is prepended to give the fully-qualified class name.

Syntax: module-name <name>
Sets the name of the generated class, overriding the default. If there is no `.' in the name, the package-prefix (specified by the -P Kawa command-line flag) is prepended.

By default, the base class of the generated module class is unspecified; you cannot count on it being more specific than Object. However, you can override it with module-extends.

Syntax: module-extends <class>
Specifies that the class generated from the immediately surrounding module should extend (be a sub-class of) the class <class>.

Syntax: module-implements <interface> ...
Specifies that the class generated from the immediately surrounding module should implement the interfaces listed.

Note that the compiler does not currently check that all the abstract methods requires by the base class or implemented interfaces are actually provided, and have the correct signatures. This will hopefully be fixed, but for now, if you are forgot a method, you will probably get a verifier error

For each top-level exported definition the compiler creates a corresponding public field with a similar (mangled) name. By default, there is some indirection: The value of the Scheme variable is not that of the field itself. Instead, the field is a gnu.mapping.Binding object, and the value Scheme variable is defined to be the value stored in the Binding. Howewer, if you specify an explicit type, then the field will have the specified type, instead of being a Binding. The indirection using Binding is also avoided if you use define-constant.

If the Scheme definition defines a procedure (which is not re-assigned in the module), then the compiler assumes the variable as bound as a constant procedure. The compiler generates one or more methods corresponding to the body of the Scheme procedure. It also generates a public field with the same name; the value of the field is an instance of a subclass of <gnu.mapping.Procedure> which when applied will execute the correct method (depending on the actual arguments). The field is used when the procedure used as a value (such as being passed as an argument to map), but when the compiler is able to do so, it will generate code to call the correct method directly.

You can control the signature of the generated method by declaring the parameter types and the return type of the method. See the applet (see section 6.4 Compiling Scheme to an applet) example for how this can be done. If the procedures has optional parameters, then the compiler will generate multiple methods, one for each argument list length. (In rare cases the default expression may be such that this is not possible, in which case an "variable argument list" method is generated instead. This only happens when there is a nested scope inside the default expression, which is very contrived.) If there are #!keyword or #!rest arguments, the compiler generate a "variable argument list" method. This is a method whose last parameter is either an array or a <list>, and whose name has $V appended to indicate the last parameter is a list.

Top-leval macros (defined using either define-syntax or defmacro) create a field whose type is currently a sub-class of kawa.lang.Syntax; this allows importing modules to detect that the field is a macro and apply the macro at compile time.

Syntax: module-static name ...
Syntax: module-static #t
Syntax: module-static #f
Control whether the generated fields and methods are static. If #t is specified, then the module will be a static module, all definitions will be static, and the module body is evaluated in the class's static initializer. Otherwise, the module is an instance module. However, the names that are explicitly listed will be compiled to static fields and methods. If #f is specified, then all exported names will be compiled to non-static (instance) fields and methods.

By default, if no module-static is specified, the following rules apply:

  1. If there is a module-extends or module-implements declaration, then (module-static #f) is implied.
  2. If the --module-static command-line parameter is specified, then (module-static #t) is implied.
  3. (Not yet implemented: If there are no top-level actions and all definitions are procedure definitions, macro definitions, or constant definitions, then (module-static #t) is implied.)
  4. Otherwise, a method will be static iff it doesn't need to reference non-static fields or methods of the module instance. In that case, the corresponding field will also be static.

Note (module-static #t) usually produces more efficient code, and is recommended if a module contains only procedure or macro definitions. (This may become the default.) However, a static module means that all environments in a JVM share the same bindings, which you may not want if you use multiple top-level environments.

Unfortuntely, the Java class verifier does not allow fields to have arbitrary names. Therefore, the name of a field that represents a Scheme variable is "mangled" (see section 10.2 Mapping Scheme names to Java names) into an acceptable Java name. The implementation can recover the original name of a field X as ((gnu.mapping.Named) X).getName() because all the standard compiler-generate field types implemented the Named interface.

The top-level actions of a module will get compiled to a run method. If there is an explicit method-extends, then the module class will also automatically implement java.lang.Runnable. (Otherwise, the class does not implement Runnable, since in that case the run method return an Object rather than void. This will likely change.)


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

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