プログラミングGauche メタオブジェクトプロトコル

『プログラミングGauche』17章総称関数とオブジェクトの練習問題をやってみました。

総称関数subは、関数呼び出しの回数と、関数実行にかかった時間を保持するクラスと、引数と結果を出力するクラスを継承しています。

このままだと、クラスが保持する時間には、クラスによるログ出力にかかった時間が含まれてしまいます。

そこで、クラスにログのON/OFFをするためのスロットlog-on(初期値#t)を追加してみました。

(use gauche.time)

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

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

(define-class <profiler-generic> (<logger-generic>)
  ((counter :init-value 0)
   (time :init-form (make <real-time-counter>))))

(define-method apply-generic ((gf <profiler-generic>) args)
  (inc! (ref gf 'counter))
  (with-time-counter (ref gf 'time) (next-method)))

(define-method get-profiles ((gf <profiler-generic>))
  (format #t "~s: ~d times called and spent time ~d\n"
          (ref gf 'name) (ref gf 'counter)
          (time-counter-value (ref gf 'time))))

(define-method init-profile ((gf <profiler-generic>))
  (set! (ref gf 'counter) 0)
  (set! (ref gf 'time) (make <real-time-counter>)))

(define-generic sub :class <profiler-generic>)

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

以下のように使います。

gosh> (get-profiles sub)
sub: 0 times called and spent time 0
#<undef>
gosh> (define val (with-output-to-string
                      (lambda ()
                          (map sub (iota 10000 100 3) (iota 10000 300 5)))))
val
gosh> (get-profiles sub)
sub: 10000 times called and spent time 1.3829899999999549
#<undef>
gosh> (init-profile sub)
#<undef>
gosh> (get-profiles sub)
sub: 0 times called and spent time 0
#<undef>
gosh> (set! (ref sub 'log-on) #f)
#<undef>
gosh> (define val (with-output-to-string
                      (lambda ()
                          (map sub (iota 10000 100 3) (iota 10000 300 5)))))
val
gosh> (get-profiles sub)
sub: 10000 times called and spent time 0.182114999999972
#<undef>