www.delorie.com/gnu/docs/kawa/kawa_66.html   search  
 
Buy GNU books!


Kawa, the Java-based Scheme system

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

10.6 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 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.

An implementation restriction is that you should only use define-class and define-simple-class in compiled code. The problem involves Java class loaders.

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 that ftype 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 define-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 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))))


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

  webmaster     delorie software   privacy  
  Copyright 2003   by The Free Software Foundation     Updated Jun 2003