This is the mail archive of the
kawa@sources.redhat.com
mailing list for the Kawa project.
Kawa now has define-class and define-simple-class
- To: kawa at sources dot redhat dot com
- Subject: Kawa now has define-class and define-simple-class
- From: Per Bothner <per at bothner dot com>
- Date: 24 Aug 2001 17:47:15 -0700
I've checked in the new syntax forms define-class and define-simple-class.
These are similar to the syntax of Guile and Stk, and also the syntax
for the existing (object ...) form. While not everything works as it
should and there are things I've haven't implemented, at this point
it should be usable. I also checked in some documentation; for
convenience, I've included it below.
Defining new classes
====================
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 Schcme
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 features of `define-class' are mostly compatible with those of
the Guile and Stk dialects of Scheme.
- Syntax: define-class name (supers ...) field-or-method-decl ...
- Syntax: define-simple-class name (supers ...) field-or-method-decl
...
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 `require'), or names for existing classes
or interfaces surrounded by `<>', such as `<gnu.lists.Sequence>'.
If `define-simple-class' is used, at most one of these may be the
name of a normal Java class or classes defined using
`define-simple-class'; the rest must be interfaces or classes
defined using `define-class'. If `define-class' is used, _all_ of
the classes listed in SUPERS should be interfaces or classes
defined using `define-class'.
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:
`type:' FTYPE
Specifies thatFTYPE is the type of (the values of) the field.
Equivalent to `:: FTYPE'.
`allocation:' `class:'
Specifies that there should be a single slot shared between
all instances of the class (and its sub-classes). Not yet
implemented for `define-class', only for
`define-simple-class'. In Java terms this is a `static'
field.
`allocation:' `instance:'
Specifies that each instance has a separate value "slot", and
they are not shared. In Java terms, this is a non-`static'
field. This is the default.
`init-form:' EXPR
An expression used to initialize the slot. The lexical
environment of the EXPR is that of the `defien-class' or
`define-simple-class'. (This is not quite true in the current
implementation, as the names of fields and methods of this
class are visible.)
`init-value:' VALUE
A value expression used to initialize the slot. For now this
is synonymous with INIT-FORM:, but that may change (depending
on what other implementation do), so to be safe only use
`init-value:' with a literal.
`init-keyword:' `NAME:'
A keyword that that can be used to initialize instance in
`make' calls. For now, this is ignored, and NAME should be
the same as the field's FNAME. `static' field.
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.
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 fix 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))))
--
--Per Bothner
per@bothner.com http://www.bothner.com/per/