gauche.mop.validator
- Slot with validator ¶Provides a metaclass that adds :validator
and :observer
slot options.
{gauche.mop.validator
}
This metaclass adds a feature that you can specify callbacks that are
called before and after the slot value is set.
For example, if you want to guarantee
that a certain slot always holds a string value, you can make a procedure
be called before the slot is modified, either by slot-ref
or
by a setter method. In the procedure you can either rejects a
value except string, or coerce the value to a string.
A validator procedure is a callback procedure that is called
before the slot value is set. It can be specified by :validator
slot option. The procedure takes two values, the instance and
the value to be set. Whatever the procedure returns is set to
the actual slot value.
A observer procedure is a callback procedure that is called
after the slot value is set. It can be specified by :observer
slot option. The procedure also takes two values, the instance
and the new value. Result of the observer procedure is discarded.
See the following example:
(define-class <v> () ((a :accessor a-of :validator (lambda (obj value) (x->string value))) (b :accessor b-of :validator (lambda (obj value) (if (integer? value) value (error "integer required for slot b"))))) :metaclass <validator-meta>) (define v (make <v>)) (slot-set! v 'a 'foo) (slot-ref v 'a) ⇒ "foo" (set! (a-of v) 1234) (a-of v) ⇒ "1234" (slot-set! v 'b 55) (slot-ref v 'b) ⇒ 55 (slot-set! v 'b 3.4) ⇒ error (set! (b-of v) 3.4) ⇒ error
You can specify default slot value (:init-value
etc.) with
:validator
. In that case, the initialization method of the
instance calls the validator with the specified default value,
if :init-keyword is not given.
(define-class <v> () ((a :initform 'foo :init-keyword :a :validator (lambda (obj value) (x->string value))))) (slot-ref (make <v>) 'a) ⇒ "foo" (slot-ref (make <v> :a 555) 'a) ⇒ "555"
It looks similar to the virtual slot, but note that a slot with validator has an actual storage in the instance, while a virtual slot doesn’t.
It is also a good example of customizing how the slots are accessed using the metaobject protocol. This feature is implemented by only a couple of dozen lines of code.