Go to the first, previous, next, last section, table of contents.
Kawa provides various ways to define, create, and access Java objects. Here are the currently supported features.
The Record package provides a facility for users to define their own
record data types. Records are extensions of the class Record
.
These procedures use the Java 1.1 reflection facility.
make-record-type
that created the type represented by rtd;
if the field-names argument is provided, it is an error if it
contains any duplicates or any symbols not in the default list.
make-record-type
that created the type represented by rtd.
make-record-type
that created the type represented by rtd.
record-predicate
, the resulting predicate would return a true
value when passed the given record.
eqv?
to the type-name argument given in
the call to make-record-type
that created the type represented by
rtd.
equal?
to the
field-names argument given in the call to make-record-type
that
created the type represented by rtd.
java.lang.Class
or a
<gnu.bytecode.ClassType>
.
The args ... are passed to the constructor of the class type.
If there is no applicable constructor, and the args ...
consist of a set of (keyword,value)-pair,
then the default constructor is called, and each
(keyword,value)-pair is used to set the correspdong slot
of the result, as if by:
(slot-set! result keyword value)
.
For example, the following are all equivalent:
(set! p (make <java.awt.Point> 3 4)) (set! p (make <java.awt.Point> y: 4 x: 3)) (set! p (make <java.awt.Point>)) (slot-set! p 'x 3) (set! (slot-ref p 'y) 4)
Kawa has both a high-level interface and a low-level interface for accessing the fields of Java objects and static fields. The lower-level interfaces are macros that return functions. These functions can be inlined, producing efficient code. The higher-level functions are less verbose and more convenient. However, they can only access public fields, and they use the slower Java reflection facility. (A possible future optimization might be for the compiler to inline direct field accesses when it knows that the object's class.)
setter
, and so can be used as the first
operand to set!
.
If name is not a valid Java name, it is "mangled" into a Java name:
For example, "file-name"
is mangled to "fileName"
.
If there is no accessible field whose name is "fieldname"
,
we look for a no-argument method whose name is "getFieldname"
.
setter
, and so can be used as the first
operand to set!
.
Examples:
(static-field <java.lang.System> 'err) ;; Copy the car field of b into a. (set! (field a 'car) (field b 'car))
(field object fieldname)
.
The following macros evaluate to procedures that can be used to access or change the fields of objects or static fields. The compiler can inline each to a single bytecode instruction (not counting type conversion).
primitive-get-field
, but used to access static fields.
Returns a zero-argument function, which when called returns
the value of the static field.
primitive-set-field
, but used to modify static fields.
Returns a one-argument function, which when called sets the
value of the static field to the argument.
Kawa has both a low-level and a high-level "Foreign Function Interface", which allows you to call any (virtual or static) Java method as if it were a Scheme procedure. The high-level one is incomplete, so I will stick to what is implemented so far.
<java.lang.Class>
, a
<gnu.bytecode.ClassType>
, or a <symbol>
or <string>
that names a Java class. The name can be <symbol>
or
<string>
that names one or more methods in the Java class.
If name is not a valid Java name, it is "mangled" into a Java name:
For example, "open-file"
is mangled to "openFile"
,
and "char?"
is mangled to "isChar"
.
Any public methods (static or instance) in the specified class (or its
super-classes) that match "name" or "name$V" collectively form a
generic procedure. When the procedure is applied to the argument list,
the most specific applicable method is chosen depending on the
argument list; that method is then
called with the given arguments. Iff the method is an instance method,
the first actual argument is used as the this
argument. If there are
no applicable methods (or no methods at all!), or there is no "best"
method, WrongType
is thrown.
("name$V" will be used for procedures with #!rest
or keyword args;
the last argument must be an array type; all the "extra" arguments
must be compatible with the type of the array elements.)
An example (derived from the Skij FAQ):
(invoke-static <java.lang.Thread> 'sleep 100)
The behavior of interpreted code and compiled code is not
indentical, though you should get the same result either way
unless you have designed the classes rather strangely. The
details will be nailed down later, but the basic idea is that
the compiler will "inline" the invoke-static
call
if it can pick a single "best" matching method.
invoke-static
.
Same as:
(lambda args (apply invoke-static (cons class (cons name args))))
The following lower-level primitives require you to specify
the parameter and return types.
Type specifications are currently required to be string literals
or one of the standard types (see section Standard Types).
A type specifier can be a fully-qualified Java class name
(for example <java.lang.StringBuffer>
). In that case,
the actual argument is cast at run time to the named class.
The specification <String>
is an exception:
It causes the toString
method of the actual
argument to be invoked.
A type specifier can also be one of the primitive Java types.
The numeric types <long>
, <int>
, <short>
,
<byte>
, <float>
, and <double>
are converted from the
corresponding Scheme number classes. Similarly, <char>
can be converted to and from Scheme characters. The type
boolean
matches any object, and the result is false
if and only if the actual argument is #f
.
The return type <void>
indicates that no value is returned.
The macros return procedure values, just like lambda
.
If the macros are used directly as the procedure of a procedure call,
then kawa can inline the correct bytecodes to call the specified methods.
(Note also that neither macro
checks that there really is a method that matches the specification.)
Otherwise, the Java reflection facility is used.
Some examples using these primitives are `vectors.scm' and `characters.scm' the directory `kawa/lib' in the Kawa sources.
field-or-method = field-decl | method-decl field-decl = (field-name [[field-type] field-init]) method-decl = ((method-name formal-arguments) [rtype] body)
Returns a new instance of a unique (anonymous) class. The class inherits from the list of supers, where at most one of the elements should be the base class being extended from, and the rest are interfaces.
Each field-decl declares a public instance field.
If field-type is given, it specifies the type of the field.
If field-init is given, it is an expression whose value
becomes the initial value of the field.
The field-init is evaluated at the same time as the object
expression is evaluated,
in a scope where all the field-names are visible.
Each method-decl declares a public non-static method,
whose name is method-name. (If method-name is not a valid
Java method name, it is mapped to something reasonable.
For example foo-bar?
is mapped to isFooBar
.)
The types of the method arguments can be specified in the
formal-arguments. The return type can be specified by rtype,
or is otherwise the type of the body.
Currently, the formal-arguments cannot contain optional, rest,
or keyword parameters. (The plan is to allow optional parameters,
implemented using multiple overloaded methods.)
The scope of the body of a method includes the field-decls of the object. It does include the surrounding lexical scope. It sort-of also includes the declared methods, but this is not working yet.
Go to the first, previous, next, last section, table of contents.