Shammer's Philosophy

My private adversaria

Lispのパッケージで可読性が・・・

パッケージを多用した際の問題点

load したファイルで in-package しているとどうなる? - Shammerismで書いた内容に近いだろうか。Lispで大きいアプリケーションを書いていると、メソッド呼出の際のパッケージ名があちこちに入ってコードが読みにくくなる。この読みにくさゆえにアプリ自体の問題点がトレースしにくくなってきてしまったので、どうにかならないものかと考えてみた。

Javaだと、文法的には一つのJavaファイルに複数のclassを書けた・・・はず(publicでないclassに限定)。しかし、運用というか可読性の観点からだろうか、実際に一つのJavaファイルには一つのclassのみを定義するのが当たり前になっている。そして、パッケージとフォルダ構造を同じにして、同じフォルダにあるクラスは全て同一パッケージとなるように開発が進められる。まあ、同じフォルダに別のパッケージのソースコードを置くこともできるが、コンパイルした際にはパッケージが分かれる。実際に動作する際に、classファイルを探すのもこのフォルダ構造とパッケージは密接に関係している、というか外からはフォルダ構造がパッケージであるかのように見える、いや、パッケージとはフォルダ構造と言ってもいい。そのため、コンパイルした後のclassファイルの配置を考えて、ソースコードもパッケージに対応したフォルダに置いておくというスタイルが確立されている。そのため、関連のあるソースは同一フォルダにあって、どこにどんなクラスのファイルがあるか、というのもわかりやすくなっている。Lispでもこれと同じように見せたい。

LispではJavaと違ってパッケージとフォルダの関連はないようだ。なので、やるとしたらソースだけを同一のフォルダに置くことになる。一方で、そもそもの発端は、他パッケージのメソッドを呼び出す際にパッケージの接頭辞をつける必要があるためにコードが読みにくくなる点を解消したいということなので、別のソースファイルで同一パッケージを定義した場合に、それらの中では同一パッケージ内のメソッド呼出はパッケージ名なしでの呼び出しが可能であることが前提になる。それを試してみる。

Sample

1.lisp
(provide 'MYPACK)

(defpackage "MYPACK"
  (:use "COMMON-LISP" "CCL" "COMMON-LISP-USER")
  (:nicknames "MYPACK"))
(in-package "MYPACK")

(defun hello (name)
  (format t "Hello, ~A~%" name))
2.lisp
(provide 'MYPACK)

(defpackage "MYPACK"
  (:use "COMMON-LISP" "CCL" "COMMON-LISP-USER")
  (:nicknames "MYPACK"))
(in-package "MYPACK")

(defun goodbye (name)
  (format t "Good-bye, ~A~%" name))
main.lisp
(load "1.lisp")
(load "2.lisp")

(in-package "MYPACK")

(hello "Taro")
(goodbye "Taro")

(quit)
main.lisp実行結果
$ ccl64 -l main.lisp 
Hello, Taro
Good-bye, Taro
$

結論

同一パッケージを複数のファイルに定義しておけば、別ファイルからも接頭辞なしでメソッド呼び出しが可能だ。