Gauche:LazyParameter

Gauche:LazyParameter

(Shiro 2018/12/05 04:31:39 UTC): 元々は、rfc.tlsdefault-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.tlsuseすることになり、循環依存でエラーになる。

次のとおり<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は排他制御をしてくれるので、他のスレッドとの競合を気にする必要もない。


最終更新 : 2018/12/05 04:31:39 UTC