For Development HEAD DRAFTSearch (procedure/syntax/module):

9.21 gauche.mop.validator - Slot with validator

Module: gauche.mop.validator

Provides a metaclass that adds :validator and :observer slot options.

Class: <validator-meta>

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



For Development HEAD DRAFTSearch (procedure/syntax/module):
DRAFT