Low-level Java access

Many implementations of a high-level language provide an interface to functions written in a lower-level language, usually C. Kawa has such a Foreign Function Interface, but the lower-level language it targets is Java. A PrimProcedure is a Procedure that invokes a specified Java method.

public class PrimProcedure
    extends ProcedureN
{ ...;
  Method method;
  Type retType;
  Type[] argTypes;

The following syntax evaluates to a PrimProcedure such that when you call it, it will invoke the static method named method-name in class class with the given arg-types and result-type:

(primitive-static-method class method-name
  return-type (arg-type ...))

When such a function is called, Kawa makes sure to convert the arguments and result between the Scheme types and Java types. For example:

   <java.lang.Character> "toUpperCase" 
   <char> (<char>))

This is a function that converts a Scheme character (represented using a <kawa.lang.Char> object), to a Java char, applies the standard java.lang.Character.toUpperCase method, and converts the result back to a Scheme character. Normally, the Java reflection features are used to call the specified method. However, if the primitive-static-method is used directly in the function position of an application, then the compiler is able to inline the PrimProcedure, and emit efficient invokestatic bytecode operations. That is the usual style, which is used to define many of the standard Scheme procedures, such as here char-upcase:

(define (char-upcase ch) 
    <java.lang.Character> "toUpperCase" 
    <char> (<char>)) 

Similar forms primitive-virtual-method and primitive-interface-method are used to generate virtual method calls and interface calls, while primitive-constructor is used to create and initialize a new object.

You can access instance and static fields of an object using similar macros. For example, to get the time-stamp from an Event, do:

((primitive-get-field <java.lang.Event>
  "when" <long>)

Kawa also has low-level operations for working with Java arrays. All these primitive operations are inlined to efficient byte code operations when the compiler knows that the procedure being called is a primitive; otherwise, the Java reflection features are used.