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-methodclassmethod-namereturn-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:
(primitive-static-method <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)
((primitive-static-method
<java.lang.Character> "toUpperCase"
<char> (<char>))
ch))
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>) evt)
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.