Shammer's Philosophy

My private adversaria

Package を使って private 引数を擬似的に実現する

Java に慣れてしまっていると、private でない変数があるというのがどうもなじめない。情報を完全にカプセル化したいという気持ちを未だに捨てることができない。Lisp でもどうにかしてこのカプセル化のようなことはできないのか、と思うが、完全には無理、、、と理解している。基本的にロードされたファイルに記述された関数や変数などは全部アクセスできる。package で定義された変数や関数を別の package からもアクセスさせたい場合には、その変数や関数を export することになっているが、別に export しなかったとしても

package::function_name

というように、パッケージ名とアクセス対象の関数や変数の間にコロンを二つ記述してやればアクセスできてしまう。カプセル化したい場合は、コロンを二つ記述するのはダメ、と自分にルールを課す必要がある。このルールを守ることで、どうにか擬似的にだがカプセル化っぽいことはできる。
以下がその例。

(defpackage "MYLIB")

(in-package mylib)

(defparameter *inner-param* "MyLibInnerParameter")

(defun get-inner-param ()
  *inner-param*)

(defun set-inner-param (value)
  (setf *inner-param* value))

(export (list 'get-inner-param 'set-inner-param))

これを mylib.lisp という名前で保存したとして、これをロードした側は以下のように使うことになる。

? (mylib:get-inner-param)
"MyLibInnerParameter"
? (mylib:set-inner-param "ValueChange")
"ValueChange"
? (mylib:get-inner-param)
"ValueChange"
? mylib:*inner-param*

> Error: Reader error: No external symbol named "*INNER-PARAM*" in package #<Package "MYLIB"> .
<-- SNIP -->
1 > q
? mylib::*inner-param*
"ValueChange"
?

コロン二つでアクセスできてしまうのはもうどうしようもなさそう。おそらく、もう完全なカプセル化というのは時代遅れなんだろうな。。。Python にも private という概念はないし。