Bigloo's object system is designed to be as simple as possible and
belongs to the 
Clos [Bobrow et al. 88] object system family
in that it uses 
classes, 
generic functions and
methods. Its design has been strongly influenced by C. Queinnec's
Meroon [Queinnec93] It does not include any meta object protocol.
Classes are defined in a module declaration. A class declaration can
take place in a compiled or interpreted module. If a class declaration
takes place in a static module clause (see Section 
Module Declaration) its scope is limited to the current module but if it
takes place in an export module clause, its scope is extended to all
modules that import the current module. The syntax of a class
declaration is:
| 
| class ident field ... | bigloo module clause |  
A class is a Bigloo type (see Section Atomic types) and the class
identifier is extracted from the <ident> of the class definition. If
<ident> is also a <typed-ident>, the type part of this identifier
denote the super-class of the class. If <ident> is a
<Ieee-ident>, the super-class of the class is the root of the
inheritance tree, the| <class> ==> (class<ident> <constructor>? <field>+)|(final-class<ident> <constructor>? <field>+)|(wide-class<ident> <constructor>? <field>+)|(abstract-class<ident> <constructor>? <field>+)<constructor> ==>(<expr>)<field> ==> <ident>
     |(<ident> <field-prop>)<field-prop> ==>read-only|(get<bigloo-exp>)|(set<bigloo-exp>)|(default<bigloo-exp>)|(info<bigloo-exp>) |  objectclass. Thisobjectclass is
the only pre-existing class.
 Final classes can only be sub-classed by wide classes.
Wide classes (only for compiled modules) can only inherit from final classes. 
abstract classes can't be instantiated.
 
 Wide-classes cannot be defined within the interpreter.
 
 The optional constructor is an expression that must evaluate to a one
argument function. This function is automatically invoked each time
a new class instance is created. The constructor is passed the fresh
instance. If a class has not defined a constructor the super class'
constructors are searched. The first constructor found is invoked. 
A constructor may be a generic function with a method specified
for one or more classes.
 
 A class field may be a typed class field which is achieved
by using a <typed-ident> instead of a <Ieee-ident>
for the <ident> value.
 
 Field marked with
 read-onlydeclaration are immutables.
 
 Defaultdeclarations allow default field values.
 For the means of an example, the traditional points and colored points 
can be defined as:
 
We illustrate final and wide classes by the example:| (module example
   (static (abstract-class pt)
           (class point::pt
              x::double 
              y::double)
           (class point-C::point 
              (color::string read-only))))
 |  
Fields may be virtual. A field is virtual as soon as its declaration
contain a| (module example
   (export (final-class person 
               (name::string (default "Jones"))
               (sex read-only)
               children::pair-nil)
           (wide-class married-person::person
               mate::person)))
 |  getattribute. Virtual fields have no 
physical implementation within the instance. When defining a virtual
field, the class declaration implements a getter and a setter
if that field is not a read only field. Access to the virtual field will
rely on invocation of the user getter and user setter. For
instance:
 
 
Virtual fields cannot be associated default values. If a virtual field
is not provided with a setter it must be annotated as read only.| (module example
   (static (class complex
              mag::double
              angle::double              
              (real::double (get (lambda (p)
                                    (with-access::complex p (mag angle)
                                       (* mag (cos angle)))))
                            read-only)
              (imag::double (get (lambda (p)
                                    (with-access::complex p (mag angle)
                                       (* mag (sin angle)))))
                            read-only))))
 (let ((p (instantiate::complex (mag 1.0) (angle 2.18))))
   (with-access::complex p (real imag)
      (print "real: " real)
      (print "imag: " imag)))
 |  
 
 Infodeclarations allow arbitrary user information field values.
This value can be retrieved by introspection, by the means of theclass-field-infointrospection function.
 For the means of an example, with add to information to the slot of
the point class.
 
| (module example
   (static (class point 
              (x::double (info '(range 0.0 10.0)))
              (y::double (info '(range -1.0 1.0)))))
 |  | 
 
| 10.2 Creating and accessing objects
 | 
Objects and classes are created and manipulated via library functions
and forms created automatically by Bigloo when a new class is defined.
| 
This function returns| isa? obj class | bigloo procedure |  #tifobjis an instance
ofclassor an instance of a sub-class ofclass, otherwise,
it returns#f. | 
| 
This forms allocates object of class| instantiate:: class(ident value)... | bigloo syntax |  classand fills the fields with
values found in the list of parameters (note that field are explicitly
named and that there is no ordering for field naming). Field values which
are not provided in the parameter list must have been declared with adefaultvalue which is used to initialize the corresponding
field.
 For instance:
 
| (module example
   (export 
      (class point (x (default 0)))
      (class point2d::point y)))
 (instantiate::point (x 0) (y 0))
(instantiate::point (y 0))
(instantiate::point (x 0))
  => Error because
 yhas no default value |  | 
| 
This function returns the NIL pre-existing class instance. This instance plays 
the role of| class-nil class | bigloo procedure |  void *in C ornullin Java. The value of each field
is unspecified but correct with respect to the Bigloo type system. Each 
call toreturns the same object (in the sense ofclass-nileq?).
 
 
| (module example
   (export 
      (class point x)
      (class point2d::point y)))
 (eq? (class-nil point) (class-nil point))
  => #t
(eq? (class-nil point) (class-nil point2d))
  => #f
 |  | 
| 
A reference to any of the variables defined in as a| with-access:: classobj (binding...) body | bigloo syntax |  bindingis
replaced by the appropriate field access form. This is true for both
reference and assignment. Abindingis either a symbol or a list
of two symbols. In the first place, it denotes a field. In the second
case, it denotes an aliases field.
 For instance:
 
| (with-access::point p (x (y1 y))
   (with-access::point p2 (y)
      (set! x (- x))
      (set! y1 (- y1 y))))
 |  | 
| 
Class instances can be accesses using the| -> varfield | bigloo syntax |  ->special form. The 
the first argument must be the identifier of a local typed variable, otherwise
an error is raised. The form->can be used to get or set value of
an instance field. For instance:
 
 
This is equivalent to:| (define (example p1::point p2::point)
   (set! (-> p1 x) (- (-> p1 x)))
   (set! (-> p1 y) (- (-> p1 y) (-> p2 y))))
 |  
| (define (example p1::point p2::point)
   (with-access::point p1 (x (y1 y))
      (with-access::point p2 (y)
         (set! x (- x))
         (set! y1 (- y1 y)))))
 |  | 
| 
This form is only available from compiled modules. In other words, it
is not available from the interpreter. It permits the creation of
recursive instances. It is specially useful for creating instances for
which class declarations contain cyclic type references (for instance
a class| co-instantiate (( varvalue) ...) body | bigloo syntax |  c1for a which a field is declared of classc2and a classc2for which a class is declared of typec1). The syntax of aco-instantiateform is similar to aletform. However the only legalvaluesareinstantiateforms. The variables introduced in the binding of aco-instantiateform are bound inbody. In addition, they
are partially bound in thevaluesexpressions. In avalueposition, a variablevarcan only be used to set the
value of a field of an instantiated class. It cannot be used in any
calculus. Example:
 
 
| (module obj-example
   (export (class c1 a b o2::c2)
           (class c2 x y o1::c1)))
 (co-instantiate ((o1 (instantiate::c1
                        (a 10)
                        (b 20)
                        (o2 o2)))
                 (o2 (instantiate::c2
                        (x 10)
                        (y 20)
                        (o1 o1))))
   (with-access::c1 o1 (o2)
      (with-access::c2 o2 (x y)
         (+ x y))))
   => 30
 |  | 
| 
This forms allocates an instance of class| duplicate:: classobj (ident value)... | bigloo syntax |  class. The field
values of the new object are picked up from the field values of
theoldobject unless they are explicitly given in the parameter
list.
 For instance:
 
is equivalent to:| (with-access::point old (x)
   (instantiate::point 
      (x x)
      (y 10)))
 |  
| (duplicate::point old (y 10))
 |  | 
 
A generic function is a bag of specific functions known as methods. When
invoked on a Bigloo object, a generic function determines the class of the
discriminating variable (corresponding to the first argument of the generic
function) and invokes the appropriate method. Generic functions implement
single inheritance and each is defined using the 
define-generic 
Bigloo syntax.
| 
A generic function can be defined with a default body which will
be evaluated if no method can be found for the discriminating
variable. The default default-body signals an error.| define-generic (name arg...) default-body | bigloo syntax |  | 
As an example, here is a possible definition of the 
object-display 
generic function:
| (define-generic (object-display obj::object . op)
   (let ((port (if (pair? op) 
                   (car op) 
                   (current-output-port))))
      (display "#\|" port)
      (display (class-name (object-class obj)) port)
      (display "\|" port)))
 | 
Methods can be defined to specialize a generic function and such
methods must have a
compatible variable list. That is, the first argument of the
method must be a sub-type (i.e. belong to a sub-class) of the
first argument of the generic function. Other formal parameters
must be of same types. Moreover, the result type of the method
must be a sub-type of the result of the generic function.
| 
| define-method (name arg...) body | bigloo syntax |  
If there is no appropriate method, an error is signaled.| call-next-method | bigloo syntax |  
 Methods can use the form
 (call-next-method)to invoke the method
that would have been called if not present. The(call-next-method)cannot be used out of method definition.
example:
| (define-method (object-display p::person . op)
   (let ((port (if (pair? op) 
                   (car op) 
                   (current-output-port))))
      (fprint port "firstname : " (-> p fname))
      (fprint port "name      : " (-> p name))
      (fprint port "sex       : " (-> p sex))
      p))
 |  | 
 
| 10.4 Widening and shrinking
 | 
Bigloo introduces a new kind of inheritance: 
widening. This allows an
object to be temporarily 
widened (that is transformed into an object
of another class, a 
wide-class) and then 
shrink-ed (that is
reshaped to its original class). This mechanism is very useful for
implementing short-term data storage. For instance, Bigloo compilation
passes are implemented using the 
widening/shrinking mechanism. On
entry to a pass, objects are widened with the specific pass fields and, on
exit from a pass, objects are shrunk in order to forget the information
related to this pass.
Only instances of 
final classes can be widened and objects can
only be widened in order to become instances of 
wide classes. 
Widening is performed by the 
widen! syntax:
| 
The object| widen!:: wide-classobj (id value) ... | bigloo syntax |  objis widened to be instance of the wide classwide-class. Fields values are either picked up from the
parameter list of thewiden!form or
from the default values in the declaration of the wide class. | 
Objects are shrunk using the 
shrink! syntax:
Here is a first example:
| (module example
   (static (final-class point 
              (x (default 0))
              (y (default 0)))
           (wide-class named-point::point name)))
 (define *point* (instantiate::point))
 | 
Two classes have been declared and an instance 
*point* of
point has been allocated. For now, 
*point* is an instance
of 
point but not an instance of 
named-point and this can
be checked by:
| (print (isa? *point* named))           ==> #t
(print (isa? *point* named-point))     ==> #f
 | 
Now, we 
widen *point*...
| (let ((n-point (widen!::named-point *point* 
                  (name "orig"))))
 | 
And we check that now, 
n-point is an instance of
named-point. Since 
named-point is a subclass of 
point, 
n-point still is an instance of 
point.
| (print (isa? n-point named-point))  ==> #t
(print (isa? n-point named))        ==> #t
 | 
Widening affects the objects themselves. It does not operate any
copy operation. Hence, 
*point* and 
n-point are 
eq?.
| (print (eq? n-point *point*))   ==> #t
 | 
To end this example, we 
shrink n-point and check 
its class.
| (shrink! n-point)
(print (isa? *point* named-point))) ==> #f
 | 
Here is a more complex example:
We illustrate widening and shrinking using our ``wedding simulator''. 
First let us define three classes, 
person (for man and woman), 
married-woman and 
married-man:
| (module wedding
   (static (final-class person 
               name::string
               fname::string
               (sex::symbol read-only))
           (wide-class married-man::person
               mate::person)
           (wide-class married-woman::person
               maiden-name::string
               mate::person)))
 | 
As we can see people are allowed to change their name but not their sex.
The identity of a person can be printed as
| (define-method (object-display p::person . op)
   (with-access::person p (name fname sex)
      (print "firstname : " fname)
      (print "name      : " name)
      (print "sex       : " sex)
      p))
 | 
A married woman's identity is printed by (we suppose an equivalent method 
definition for married-man)
| (define-method (object-display p::married-woman . op)
   (with-access::married-woman p (name fname sex mate)
      (call-next-method)
      (print "married to: " mate) 
      p))
 | 
We create a person with the 
birth function:
| (define (birth name::string fname::string sex)
   [assert (sex) (memq sex '(male female))]
   (instantiate::person 
      (name name)
      (fname fname)
      (sex sex)))
 | 
We celebrate a wedding using the 
get-married! function:
| (define (get-married! woman::person man::person)
   (if (not (and (eq? (-> woman sex) 'female)
                 (eq? (-> man sex) 'male)))
       (error "get-married" 
              "Illegal wedding" 
              (cons woman man))
       (let* ((mname (-> woman name))
              (wife  (widen!::married-woman woman
                      (maiden-name mname)
                      (mate man))))
          (person-name-set! wife (-> man name))
          (widen!::married-man man
             (mate woman)))))
 | 
We can check if two people are married by
| (define (couple? woman::person man::person)
   (and (isa? woman married-woman)
        (isa? man married-man)
        (eq? (with-access::married-woman woman (mate) mate) man)
        (eq? (with-access::married-man man (mate) mate) woman)))
 | 
Now let us study the life a 
Junior Jones and
Pamela Smith. Once upon a time...
| (define *junior* (birth "Jones" "Junior" 'male))
(define *pamela* (birth "Smith" "Pamela" 'female))
 | 
Later on, they met each other and ... they got married:
| (define *old-boy-junior* *junior*)
(define *old-girl-pamela* *pamela*)
(get-married! *pamela* *junior*)
 | 
This union can be checked:
| (couple? *pamela* *junior*)               
   => #t
 | 
We can look at the new identity of 
*pamela*
| (print *pamela*)
   -| name      : Jones
      firstname : Pamela
      sex       : FEMALE
      married to: Junior Jones
 | 
But 
*pamela* and 
*junior* still are the same persons:
| (print (eq? *old-boy-junior* *junior*))   => #t
(print (eq? *old-girl-pamela* *pamela*))  => #t
 | 
Unfortunately all days are not happy days. After having been married
*pamela* and 
*junior* have divorced:
| (define (divorce! woman::person man::person)
   (if (not (couple? woman man))
       (error "divorce!"
              "Illegal divorce"
              (cons woman man))
       (with-access::married-woman woman (maiden-name)
          (begin
             (shrink! woman)
             (set! (-> woman name) maiden-name))
          (shrink! man))))
 (divorce! *pamela* *junior*)
 | 
We can look at the new identity of 
*pamela*
| (print *pamela*)
   -| name      : Smith
      firstname : Pamela
      sex       : FEMALE
 | 
And 
*pamela* and 
*junior* still are the same persons:
| (print (eq? *old-boy-junior* *junior*))   => #t
(print (eq? *old-girl-pamela* *pamela*))  => #t
 | 
 
No type denotes Bigloo's classes. These objects are handled
by the following library functions:
| 
Returns, if any, the class named| find-class symbol | bigloo procedure |  symbol. | 
| 
Returns| class? obj | bigloo procedure |  #tif and only ifobjis a class. | 
| 
Returns the super-class of| class-super class | bigloo procedure |  class. | 
| 
Returns the subclasses of| class-subclasses class | bigloo procedure |  class. | 
| 
Returns the name (a symbol) of| class-name class | bigloo procedure |  class. | 
| 
Returns| object-constructor class | bigloo procedure |  class's constructor. | 
| 
Returns the class that| object-class object | bigloo procedure |  objectbelongs to. | 
| 
Returns| wide-object? object | bigloo procedure |  #tifobjectis a wide object otherwise it returns#f. | 
| 
This generic function is invoked by| object-display object [port] | bigloo generic |  displayto display objects. | 
| 
This generic function is invoked by| object-write object [port] | bigloo generic |  writeto write objects. | 
| 
| object->struct object | bigloo generic |  
These functions converts objects into Scheme structures and vice-versa.| struct->object struct | bigloo procedure |  | 
| 
This generic function is invoked by| object-equal? object obj | bigloo generic |  equal?when the first argument
is an instance ofobject. | 
| 
This generic function returns an hash number of| object-hashnumber object | bigloo generic |  object. | 
| 
Returns| is-a? obj class | bigloo procedure |  #tifobjbelongs toclassotherwise it
returns#f. | 
 
 
| 10.6 Object serialization
 | 
Objects can be 
serialized and 
un-serialized using
the regular 
string->obj and 
obj->string
functions. Objects can be stored on disk and restored from disk
by the use of the 
output-obj and 
input-obj
functions.
In addition to this standard serialization mechanism, custom object
serializers and un-serializers can be specified by the means of the
register-class-serialization! function (see Section
Serialization.
 
Two objects can be compared with the 
equal? function. Two object
are equal if and only if they belong to a same class, all their field
values are equal and all their super class's field values are equal.
 
Bigloo provides the programmer with some object introspection facilities.
See section see 
Object library for information on classes and
objects handling. Introspection facilities are, by default, available
for all classes. However, in order to shrink the code size generation,
it may be useful to disable class introspection. This decision can be
taken on a per class basis (i.e., one class may be provided with
introspection facilities while another one is not). The compiler
option 
-fno-reflection 
(see Chapter 
Compiler Description) prevents the
compiler to generate the code required for introspecting the classes
defined in the compiled module.
| 
Returns the a description of the fields of| class-fields class | bigloo procedure |  class. This description
is a list of field descriptions where each field description can be accessed by
the means of the following library functions. The fields are those 
directly defined inclass. That isclass-fieldsdoes not
return fields defined in super classes ofclass. | 
| 
Returns the a description of the fields of| class-all-fields class | bigloo procedure |  class. This description
is a list of field descriptions where each field description can be accessed by
the means of the following library functions. By contrast withclass-fields, this function returns fields that are also defined in
the super classes ofclass.
in th | 
| 
Returns the field named| find-class-field class symbol | bigloo procedure |  symbolfrom classclass. Returns#fis such a field does not exist. | 
| 
Returns #t if| class-field? obj | bigloo procedure |  objis a class field descriptor. Otherwise returns #f. | 
| 
Returns the name of the| class-field-name field | bigloo procedure |  field. The name is a symbol. | 
| 
Returns a procedure of one argument. Applying this function to an object
returns the value of the field described by| class-field-accessor field | bigloo procedure |  field. | 
| 
Returns| class-field-mutable? field | bigloo procedure |  #tif the described field is mutable and#fotherwise. | 
| 
Returns a procedure of two arguments. Applying this function to an object
changes the value of the field described by| class-field-mutator field | bigloo procedure |  field. It is an
error to applyclass-field-mutatorto an immutable field. | 
| 
Returns the information associated to| class-field-info field | bigloo procedure |  field(this the class declarationinfoattribute). | 
For means of an example, here is a possible implementation of the
equal? test for objects:
| (define (object-equal? obj1 obj2)
   (define (class-field-equal? fd)
      (let ((get-value (class-field-accessor fd)))
          (equal? (get-value obj1) (get-value obj2))))
   (let ((class1 (object-class obj1))
         (class2 (object-class obj2)))
      (cond
         ((not (eq? class1 class2))
          #f)
         (else
          (let loop ((fields (class-fields class1))
                     (class  class1))
             (cond
                ((null? fields)
                 (let ((super (class-super class)))
                    (if (class? super)
                        (loop (class-fields super)
                              super)
                        #t)))
                ((class-field-equal? (car fields))
                 (loop (cdr fields) class))
                (else
                 #f)))))))
 | 
| 
Returns the creator for| class-creator class | bigloo procedure |  class. The creator is a function for which
the arity depends on the number of slots the class provides 
(see Section see Creating and accessing objects).
 When an instance is allocated by the means of the
 class-creator, as
for direct instantiation, the class constructor is 
automatically invoked.
Example:
| (module foo
   (main main)
   (static (class c1 (c1-constructor))))
 (define c1-constructor
   (let ((count 0))
      (lambda (inst)
	 (set! count (+ 1 count))
	 (print "creating instance: " count)
	 inst)))
 
 (define (main argv)
   (let ((o1 (instantiate::c1))
	 (o2 (instantiate::c1))
	 (o3 ((class-creator c1))))
      'done))
   -| creating instance: 1
      creating instance: 2
      creating instance: 3
 |  | 
| 
Returns the predicate for| class-predicate class | bigloo procedure |  class. This predicate returns#twhen applied to object of typeclass. It returns#fotherwise. |