(Shiro 2018/12/05 04:31:39 UTC):
元々は、rfc.tls
のdefault-tls-class
パラメータの実装で困ったのが発端。rfc.tls
はバックエンドとしてaxTLSとmbedTLSをサポートしていて、configure時に選べる。default-tls-class
は、どちらのサポートも無ければ#f
に、axTLSのサポートが入っていれば<ax-tls>
に、axTLSが無くてmbedTLSが入っていれば<mbed-tls>
に初期化される。
ところで、mbedTLSのサポートはライセンスの関係上バイナリを分けておきたい。そこで、mbedTLSに関わる部分はrfc.tls.mbed
というモジュールに切り離し、rfc.tls
内で<mbed-tls>
をautoload設定している。(use rfc.tls)
して<mbed-tls>
を参照した途端、rfc.tls.mbed
がautoloadされるという仕掛けだ。
ここで、default-tls-class
を<mbed-tls>
で初期化する部分が問題になる。rfc.tls
中で
(cond-expane ... mbedTLSだけがサポートされている場合 ... (define default-tls-class (make-parameter <mbed-tls>)) )
などとやってしまうと、default-tls-class
を定義しようとした時点で<mbed-tls>
が評価され、autoloadがトリガされてしまう。 rfc.tls.mbed
は(use rfc.tls)
しているので、rfc.tls
中にrfc.tls
をuse
することになり、循環依存でエラーになる。
次のとおり<mbed-tls>
の評価を遅延すれば循環依存は避けられるが:
(define default-tls-class (make-parameter (delay <mbed-tls>)))
この場合、(default-tls-class)
はPromiseを返すので、いちいちforce
してやらねばならない。使う側が「このパラメータはforceしないとならない」って気にするのは抽象化の漏れだし、既にdefault-tls-class
を使ってるところを書き直さなければならない。
そこで、「参照時に自動的にforceする」という属性をパラメータに持たせることを考えた。
Promiseを返したいパラメータもあるだろうから、デフォルトは今まで通りで、作成時にLAZY_PARAMETER
フラグを渡したら値を取り出す時にforceする。
この機能はrfc.tls
の例だけでなく、一般に「グローバルな値を計算で生成したいが、重い処理なので本当に必要な時まで計算を遅らせたい」という用途に使える。delay/forceは排他制御をしてくれるので、他のスレッドとの競合を気にする必要もない。