Node:Defining new classes, Next:Anonymous classes, Previous:Field operations, Up:Objects Classes and Modules
Kawa provides various mechanisms for defining new classes.
The define-class and define-simple-class forms
will usually be the preferred mechanisms. They have basically
the same syntax, but have a couple of differences.
define-class allows multiple inheritance as well as true nested
(first-class) class objects. However, the implementation
is more complex: code using it is slightly slower, and the mapping to
Java classes is a little less obvious. (Each Scheme class is implemented
as a pair of an interface and an implementation class.)
A class defined by define-simple-class is slightly more
efficient, and it is easier to access it from Java code.
The syntax of define-class are mostly compatible with that
in the Guile and Stk dialects of Scheme.
| define-class name (supers ...) field-or-method-decl ... | Syntax |
| define-simple-class name (supers ...) field-or-method-decl ... | Syntax |
field-or-method ::= field-decl | method-decl
field-decl ::= (fname [:: ftype] [option-keyword option-value]*)
method-decl ::= ((method-name formal-arguments) [:: rtype] body)
Defines a new class named name. If define-simple-class is
used, creates a normal Java class named name in the current package.
(If name has the form <xyx> the Java implementation
type is named xyz.) If define-class the implementation is
unspecified. In most cases, the compiler creates a class pair,
consisting of a Java interface and a Java implementation class.
The class inherits from the classes and interfaces listed in supers.
This is a list of names of classes that are in scope (perhaps imported
using Each field-decl declares a public instance "slot" (field) with the given fname. If ftype is specified it is the type of the slot. The following option-keywords are implemented:
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 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. |
A simple example:
(define-simple-class <2d-vector> ()
(x type: <double> init-value: 0.0 init-keyword: x:)
(y type: <double> init-value: 0.0 init-keyword: y:)
((add (other :: <2d-vector>)) :: <2d-vector>
;; Kawa compiles this using primitive Java types!
(make <2d-vector>
x: (+ x (slot-ref other 'x))
y: (+ y (slot-ref other 'y))))
((scale (factor :: <double>)) :: <2d-vector>
;; Unfortunately, multiply is not yet optimized as addition is.
(make <2d-vector> x: (* factor x) y: (* factor y))))
(define-simple-class <3d-vector> (<2d-vector>)
(z type: <double> init-value: 0.0 init-keyword: z:)
((scale (factor :: <double>)) :: <2d-vector>
;; Note we cannot override the return type to <3d-vector>
;; because Java does not allow that. Should hide that. .
(make <3d-vector>
;; Unfortunately, slot names of inherited classes are not visible.
;; Until this is fixed, use slot-ref.
x: (* factor (slot-ref (this) 'x))
y: (* factor (slot-ref (this) 'y))
z: (* factor z))))