メソッド適用のカスタマイズ

プログラミングGaucheの[17.5.3 メソッドの適用のカスタマイズ]の内容を復習。

総称関数を標準のクラスのインスタンスではなく、これを継承した独自のクラスのインスタンスとすることによりメソッドの適用方法をカスタマイズ(今回はログ出力)する。

総称関数クラス

まず、を継承したクラスを定義。ログのon/offを制御する目的のenable-logというスロットを含める。

(define-class <logger-generic> (<generic>)
  ( (enable-log :init-keyword :enable-log :init-value #t) 
))

総称関数

上記で定義した総称関数クラス()のインスタンスとして総称関数を定義。ここで:classオプションを指定しなければ標準のインスタンスとなる。

(define-generic add :class <logger-generic> )
(define-generic sub :class <logger-generic> )

総称関数へのメソッド適用変更

上記で定義した総称関数クラスに対して適用方法を変えるため。その総称関数クラスに対するapply-genericメソッドを定義。このapply-generic自体も総称関数である。
next-methodを呼び出すことにより、適当された通常のメソッド呼び出しがされる。
ここでは、そのメソッド呼び出しの前にメソッド引数の表示、後に結果の表示を行う。

(define-method apply-generic ((gf <logger-generic>) args)
  (when (ref gf 'enable-log) 
   (format #t "args: ~s\n" args) )
  (let ((return-value (next-method)))
    (when (ref gf 'enable-log) 
          (format #t "result: ~s\n" return-value) )
    return-value)
)

総称関数へのメソッド追加

ここでは、数値の単純な足し算、引き算を定義。

(define-method add ((num1 <number>) (num2 <number> ))
  (+ num1 num2)
)

(define-method sub ((num1 <number>) (num2 <number> ))
  (- num1 num2)
)

総称関数クラスのスロットを変更するメソッド

総称関数クラスのスロットの値を変更して、メソッドの適用を変更させる(ここでは、ログ出力のon/offを切り替える)。

(define-method enable-log ((gf <logger-generic>) bool)
  (set! (ref gf  'enable-log) bool)

確認

上記をgoshに読み込ませてから、以下のように確認
1回目のaddメソッドでは、引数と結果が出力され、enable-logメソッドでログ抑制されてからは、それらは出力されない。

gosh>(add 3 4)
args: (3 4)
result: 7
7
gosh> (enable-log add #f)
#<undef>
gosh> (add 3 4)
7