Next: Generic function and method, Previous: Class, Up: Object system [Contents][Index]
In this section, we explain how to create and use an instance.
• Creating instance: | ||
• Accessing instance: | ||
• Changing classes: |
Next: Accessing instance, Previous: Instance, Up: Instance [Contents][Index]
Using class object, you can create an instance of the class
by a generic function make
.
A specialized method for standard <class>
is defined:
Creates an instance of class and returns it. Arg … is typically a keyword-value list to initialize the instance.
Conceptually, the default make
method is defined
as follows:
(define-method make ((class <class>) . initargs) (let ((obj (allocate-instance class initargs))) (initialize obj initargs) obj))
That is, first it allocates memory for class’s instance,
then initialize it with the initialize
method.
Returns a newly-allocated uninitialized instance of class.
The default initialize method for <object>
works as follows:
Among the default slot allocation classes, only
instance-allocated slots are initializable and are handled by
the above sequence. Class-allocated slots (e.g. its
slot allocation is either :class
or :each-subclass
)
are initialized when the class object is created, if
:init-value
or :init-form
slot option is given.
Virtual slots aren’t initialized at all.
An user-defined allocation class can be configured either initializable or not initializable; see Metaobject protocol for the details.
If you specialize initialize
method, make sure to call
next-method
so that the slots are properly initialized
by the default sequence, before accessing any slot of the
newly created instance.
Typically you specialize initialize
method for
your class to customize how the instance is initialized.
It is not common to specialize allocate-instance
method.
However, knowing that how make
works, you can specialize
make
itself to avoid allocation of instance in
some circumstances (e.g. using pre-allocated instances).
Next: Changing classes, Previous: Creating instance, Up: Instance [Contents][Index]
Returns a value of the slot slot of object obj.
If the specified slot is not bound to any value, a generic function
slot-unbound
is called with three arguments, obj’s class,
obj, and slot. The default behavior of slot-unbound
is to signal an error.
If the object doesn’t have the specified slot,
a generic function slot-missing
is called with three
arguments, obj’s class,
obj, and slot. The default behavior of slot-missing
is to signal an error.
Alters the value of the slot slot of object obj to the value value.
If the object doesn’t have the specified slot, a generic function
slot-missing
is called with four arguments,
obj’s class, obj, slot, value.
Returns true if object obj’s slot slot is bound, otherwise returns false.
If the object doesn’t have the specified slot, a generic function
slot-missing
is called with three arguments,
obj’s class, obj, slot.
Returns true if obj has the slot named slot.
This function implements the common idiom. It can be defined like the following code (but it may be optimized in the future versions).
(define (slot-push! obj slot value) (slot-set! obj slot (cons value (slot-ref obj slot))))
Reverse operation of slot-push!
.
If the value of slot of obj
is a pair, removes its car and returns the removed item.
When the value of slot is not a pair, or the slot is unbound, fallback is returned if it is provided, otherwise an error is signaled.
These methods just calls slot-ref
and slot-set!
, respectively.
They are slightly less efficient than directly calling slot-ref
and slot-set!
, but more compact in the program code.
This generic function is called when an unbound slot value is retrieved. The return value of this generic function will be returned to the caller that tried to get the value.
The default method just signals an error.
This generic function is called when a non-existent slot value is retrieved or set. The return value of this generic function will be returned to the caller that tried to get the value.
The default method just signals an error.
Returns a class metaobject of obj. If obj’s class has been redefined, but obj is not updated for the change, then this procedure returns the original class of obj without updating obj.
You need this procedure in rare occasions, such as within
change-class
method, in which you don’t want to trigger
updating obj (which would cause infinite loop).
When slot’s :allocation
option is either :class
or :each-subclass
, these procedures allow you to
get/set the value of the slot without having an instance.
Generic function version of slot-ref
, slot-set!
and
slot-bound?
. Class must be the class of obj.
Besides being generic, these functions are different from their procedural versions that they don’t trigger class redefinition when obj’s class has been redefined (i.e. in which case, class should be the original class of obj).
Note: Unlike CLOS, slot-ref
etc. don’t call the generic
function version in it, so you can’t customize the behavior
of slot-ref
by specializing slot-ref-using-class
.
So the primary purpose of those generic functions are to be
used within change-class
method; especially, slot-ref
etc.
can’t be used during obj’s being redefined, since they
trigger class redefinition again (see Changing classes for details).
Previous: Accessing instance, Up: Instance [Contents][Index]
An unique feature of CLOS-family object system is that you can change classes of an existing instance. The two classes doesn’t need to be related; you can change a sewing machine into an umbrella, if you like.
Changes an object obj’s class to new-class.
The default method just calls change-object-class
procedure.
Changes an object obj’s class from orig-class to new-class. This isn’t a generic function—changing object’s class needs some secret magic, and this procedure encapsulates it.
The precise steps of changing class are as follow:
allocate-instance
.
Note that initialize
method of new-class
isn’t called on obj.
If you desire, you can call it by your own change-class
method.
Change-object-class
returns obj.
Usually a user is not supposed to call change-object-class
directly.
Instead, she can define a specialized change-class
. For example,
if she wants to carry over the slot x
of old class to the
slot y
of new class, she may write something like this:
(define-method change-class ((obj <old-class>) <new-class>) (let ((old-val (slot-ref obj 'x))) (next-method) ;; calls default change-class (slot-set! obj 'y old-val) ;; here, obj's class is already <new-class>. obj))
Updating an instance for a redefined class is also handled
as class change. When an object is accessed via normal
slot accessor/modifier, its class is checked whether
it has been redefined. And if it has indeed been redefined,
change-class
is called with the
redefined class as new-class; that is, updating
an instance is regarded as changing object’s class from
the original one to the redefined one.
By specializing change-class
, you can customize the
way an instance is updated for a redefined class.
However, you need a special care to write change-class
for class redefinition.
First, the redefinition changes global binding of the class object.
So you need to keep the reference to the old class before
redefining the class, and use the old class to specialize
change-class
method:
;; save old <myclass> (define <old-myclass> <myclass>) ;; redefine <myclass> (define-class <myclass> () ...) ;; define customized change-class method (define-method change-class ((obj <old-myclass>) <myclass>) ... (next-method) ...)
Next, note that the above change-class
method may be
triggered implicitly when you access to obj via
slot-ref
, slot-set!
, class-of
, etc.
If you use such procedures like slot-ref
on obj
again within change-class
, it would trigger the
instance update protocol recursively, which would cause
an infinite loop.
You can only use the methods that doesn’t trigger
instance update, that is, slot-ref-using-class
,
slot-set-using-class!
, slot-bound-using-class?
and current-class-of
.
If you want to carry over a slot whose value is calculated
procedurally, such as a virtual slot, then slot-ref
etc.
might be called implicitly on obj during calculating the
slot value. Actually change-object-class
has a
special protection to detect such a recursion. If that
happens, change-object-class
gives up to retrieve
the slot value and just initializes the slot of the new instance
as if the old slot were unbound.
Customizing instance update is highly tricky business,
although very powerful. You can find some nontrivial
cases in the test program of Gauche source code;
take a look at test/object.scm
.
Next: Generic function and method, Previous: Class, Up: Object system [Contents][Index]