Kawa provides various ways to define, create, and access Java objects. Here are the currently supported features.
this" is a macro, not a variable, so you have to write
it using parentheses: `(this)'. A planned extension will
allow an optional class specifier (needed for nested clases).
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.Programs use "names" to refer to various values and procedures. The definition of what is a "name" is different in different programming languages. A name in Scheme (and other Lisp-like languages) can be principle contain any character (if using a suitable quoting convention), but typically names consist of "words" (one or more letters) separated by hyphens, such as `make-temporary-file'. Digits and some special symbols are also used. Standard Scheme is case-insensitive; this means that the names `loop', `Loop', and `LOOP' are all the same name. Kawa is by default case-sensitive, but we recommend that you avoid using upper-case letters as a general rule.
The Java language and the Java virtual machine uses names for classes, variables, fields and methods. These names can contain upper- and lower-case letters, digits, and the special symbols `_' and `$'.
Given a name in a Scheme program, Kawa needs to map that name into a valid Java name. A typical Scheme name such as `make-temporary-file' is not a valid Java name. The convention for Java names is to use "mixed-case" words, such as `makeTemporaryFile'. So Kawa will translate a Scheme-style name into a Java-style name. The basic rule is simple: Hyphens are dropped, and a letter that follows a hyphen is translated to its upper-case (actually "title-case") equivalent. Otherwise, letters are translated as is.
Some special characters are handled specially. A final `?' is replaced by an initial `is', with the following letter converted to titlecase. Thus `number?' is converted to `isNumber' (which fits with Java conventions), and `file-exists?' is converted to `isFileExists' (which doesn't really). The pair `->' is translated to `To', and if followed by a letter, that is is converted to titlecase. For example `list->string' is translated to `listToString'.
Other special characters are translated in uglier ways, using a mapping scheme that is likely to change in future versions.
Note that this mapping may map different Scheme names to the same Java name. For example `string?', `String?', `is-string', `is-String', and `isString' are all mapped to the same Java identifier `isString'. Code that uses such "Java-clashing" names is not supported. There is very partial support for renaming names in the case of a clash, and there may be better support in the future. However, some of the nice features of Kawa depend on being able to map Scheme name to Java names naturally, so we urge you to not write code that "mixes" naming conventions by using (say) the names `open-file' and `openFile' to name two different objects.
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)-pairs,
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 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.
<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.
The name is "mangled" (see section Mapping Scheme names to Java names) into a valid Java name.
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" is 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.
<symbol> or
<string> that names one or more methods in the Java class.
The name is "mangled" (see section Mapping Scheme names to Java names) into a valid Java name.
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 object is used as the this argument;
otherwise object is prepended to the args list. If there are
no applicable methods (or no methods at all!), or there is no "best"
method, WrongType is thrown.
("name$V" is 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.)
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))))
Some examples using these functions are `vectors.scm' and `characters.scm' the directory `kawa/lib' in the Kawa sources.
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.
setter, and so can be used as the first
operand to set!.
The field name is "mangled" (see section Mapping Scheme names to Java names) into a valid Java name.
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).
(set! (field object fieldname) value).
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.