#:g1: cl-package-locksの紹介

Posted 2014-07-09 16:30:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の191日目です。

cl-package-locksとはなにか

 cl-package-locksは、Elliott Johnson氏作のポータブルなパッケージロック機構を提供するライブラリです。

パッケージ情報

パッケージ名cl-package-locks
Quicklisp
CLiKiCLiki: CL-PACKAGE-LOCKS
Quickdocscl-package-locks | Quickdocs
CL Test Grid: ビルド状況cl-package-locks | CL Test Grid

インストール方法

(ql:quickload :cl-package-locks)

試してみる

 どんな関数があるかは、Quickdocsで確認できます。

 そもそもパッケージロックとは何かというと、(再)定義されるシンボルのパッケージがロックされている場合、*package*が該当パッケージでなければエラーとするものです。コードにすると

(defpackage dalto
  (:use :cl)
  (:export :foo)) 

(defpackage milwa (:use :cl :dalto))

(lock-package (find-package :dalto))

(let ((*package* (find-package :dalto))) (eval '(defun milwa::foo (n) n))) ;=> DALTO:FOO

(let ((*package* (find-package :milwa))) (eval '(defun milwa::foo (n) n))) ;!!> Lock on package DALTO violated when interning FOO while in ;!!> package COMMON-LISP-USER.

という感じなのですが、これで何ができるかというと、エクスポートされたシンボルを上書き定義してしまうことを防止できます。
Quicklisp等で配布されているライブラリでも他のシンボルを再定義してしまっているのが実際に結構存在したりしますが、この辺りは動的に定義できることの短所でもあるかなと思います。
ということで、この問題の対応策としてのパッケージロックなのですが、ANSI CLで定義された機能ではなく、処理系が拡張機能としてサポートしている機能になります。

 cl-package-locksが対応している処理系は現在のところ、Allegro CL、CLISP、CMUCL、SBCLのようですが、下記のように使えます。

(in-package :cl-package-locks) 

;;; daltoパッケージはロックされているか (package-locked-p :dalto) ;=> NIL ;;; daltoパッケージをロック (lock-package (find-package :dalto)) ;=> T ;;; daltoパッケージに関数を追加 => パッケージロックエラー (defun dalto::foo (n) n) ;!!> Lock on package DALTO violated when interning FOO while in ;!!> package COMMON-LISP-USER. ;;; パッケージロックを解除 (unlock-package :dalto) ;=> T

(defun dalto::foo (n) n) ;=> DALTO::FOO

;;; 複数のパッケージを一括処理 (let ((pkgs (resolve-packages '(:cl-package-locks :swank)))) (lock-packages pkgs) ; your code here (unlock-packages pkgs)) ;=> NIL

(lock-package (find-package :dalto)) ;=> T ;;; パッケージの一時ロック解除 (with-packages-unlocked (dalto) (defun dalto::foo (n) n)) ;=> DALTO::FOO

;;; 全パッケージロックを一時解除する (without-package-locks (defun dalto::foo (n) n)) ;=> DALTO::FOO

;;; パッケージロックされていないパッケージのリスト (all-unlocked-packages) ;=> (#<PACKAGE "CL-PACKAGE-LOCKS"> #<PACKAGE "SWANK-TRACE-DIALOG"> ; #<PACKAGE "CL-OAUTH-PATCH.INTERNAL"> #<PACKAGE "CL-OAUTH-PATCH"> ;...

;;; パッケージロック中のパッケージのリスト (all-locked-packages) ;=> (#<PACKAGE "CL-WHO"> #<PACKAGE "IT.BESE.FIVEAM"> #<PACKAGE "ALEXANDRIA.0.DEV"> ; #<PACKAGE "SB-LOOP"> #<PACKAGE "SB-EVAL"> #<PACKAGE "SB-WALKER"> ; #<PACKAGE "SB-UNIX"> #<PACKAGE "SB-SEQUENCE"> #<PACKAGE "SB-PROFILE"> ; #<PACKAGE "SB-PRETTY"> #<PACKAGE "SB-REGALLOC"> #<PACKAGE "SB-MOP"> ; #<PACKAGE "SB-THREAD"> #<PACKAGE "SB-GRAY"> #<PACKAGE "SB-FORMAT"> ; #<PACKAGE "SB-FASL"> #<PACKAGE "SB-DISASSEM"> #<PACKAGE "SB-DEBUG"> ; #<PACKAGE "SB-C"> #<PACKAGE "SB-BIGNUM"> #<PACKAGE "SB-ASSEM"> ; #<PACKAGE "SB-ALIEN"> #<PACKAGE "SB-PCL"> #<PACKAGE "SB-ALIEN-INTERNALS"> ; #<PACKAGE "SB-DI"> #<PACKAGE "SB-IMPL"> #<PACKAGE "SB-SYS"> ; #<PACKAGE "SB-KERNEL"> #<PACKAGE "SB-VM"> #<PACKAGE "SB-INT"> ; #<PACKAGE "SB-EXT"> #<PACKAGE "COMMON-LISP">)

まとめ

 今回は、cl-package-locksを紹介してみました。
パッケージのロックは、Quicklispのような公のライブラリ集に登録するのであれば必須にした方が良い位だと自分は思いますが、実際にロックしているライブラリは少ないですね。

comments powered by Disqus