C++ と CLOS

C++ のプログラムを、勉強として CLOS に書き換えている。C++ も CLOS も両方勉強しているから当たり前だが、これがなかなか難しい。

今のところ、素朴に C++ のクラス定義をそのまま CLOS のクラスに変換しているが、以下のような違和感を感じている。

  • CLOS ではメソッドがクラスに属するわけではないので、C++ のメソッドを Common Lisp の defmethod で書くと毎回 this 相当のインスタンスを引数に渡すことになり、コードが煩雑。Python っぽい。
  • C++ の基本クラス(String クラスなど)はなかなか充実しているが、CLOS には相当するものがない。正確には存在するがより低レベルなものしか無い感じ。
  • メソッド名。CLOS の仮引数リストは固定的なので、C++ のクラスで使える length のような言語の組み込み関数と同じメソッド名が使いにくい。(使いにくい、と書いたのは、方法がちゃんとあるはずだから。調査不足。)
  • C++ で書かれたよいクラスは、 CLOS に焼き直すととても lisp っぽくない副作用だらけのコードになる、気がする。
  • C++ っぽく書いた下手な lisp コードは、全部書き上がらないとテストできない。もっと小さい単位でテストできるようにすると、やっぱり C++ っぽく書くだけではだめで、ほとんど全部、 lisp らしく書き換えなくてはならないかもしれない。

もうしばらく手を動かしてみよう。

追記

Peter Seibel "Practical Common Lisp", Chapter 21 にきちんと説明があった。独自パッケージ :foobar で :common-lisp パッケージを use していて、かつ、length というメソッドを作りたい場合は以下のようにする。

;; -*- mode: common-lisp; package: foobar; -*-
(defpackage :foobar
  (:use :common-lisp)
  (:shadow :length)
  )

(in-package :foobar)

(defclass seq ()
  ((data :accessor seq-data :initform nil :initarg :data)))

(defmethod length ((seq seq))
  (cl:length (seq-data seq)))

shadow によって、 :foobar パッケージの length が定義できるようになった。代わりに、 :common-lisp パッケージの length を参照するのが若干煩雑になっている。当たり前といえば当たり前だが、若干不便。

はてなd:id:sumin (オブジェクト指向についてためになる)氏の記事も参考になった。