2016-12-21-01-CL-OPERATOR:clonableの代入時コピールールを変更 - project-enigma

2016-12-21-01-CL-OPERATOR:clonableの代入時コピールールを変更

>> Site top >> weblog >> 月別アーカイブ >> 2016年12月のlog >> 2016-12-21-01-CL-OPERATOR:clonableの代入時コピールールを変更

最終更新日付:2016/12/21 07:13:18


CL-OPERATOR:clonableの代入時コピールールを変更

2016 年 12 月 21 日

うん、変更した。元々の挙動は仕様通りだったはずなんだけど、その仕様がそもそもおかしかったので、改善というよりはバグフィックスだな。

CL-OPERATOR にせよ CL-STL にせよ、そこまで使ってくれている人はいない認識なのだけれど、一応ちゃんと書いておこう。_= マクロが展開する総称関数呼び出し operator_= 呼び出しが代入処理を扱うのだけれど、代入元が clonable だった場合、一般的には「値のコピー」が行なわれる。代入先が同じ型のオブジェクトだった場合の実装はそのクラスで定義する必要があるのだけれど、それ以外の場合は CL-OPERATOR が定義するデフォルトの挙動になるわけだ。今回、そのデフォルトの挙動に問題があることが判明した。具体的には、デフォルトの挙動は以下のようになっていた。

(defmethod operator_=  (a b)
  b)
(defmethod operator_= ((a (eql nil)) (b clonable))
  (clone b))

 

つまり、代入先が nil の場合のみコピーをするようになっていたわけだ。そして前述の通り、同じタイプ同士の代入については(必要なら)独自に defmethod しなさいよ、というルールになっている。問題は、「代入先が nil でも同じタイプのオブジェクトでもない場合」はどうなるのか、どうなるべきか、ということだ。

どうなるのか、という点については、実装から明らかな通り、clonable といえどもコピーは行なわず、setq と同じ要領で値の共有が行なわれる。たしかにそういう仕様だった。でも、この仕様はおかしかったのだ。理由は、代入先について良くわからない場合があるからだ。それは CL-STL を使っている時に気付いた。コンテナに対してinsert メソッドをかける時、内部で要素の移動が発生する場合なんかがそうだ(実例は改めて書くかもしれない)。そんなわけで、先の clonable に対するデフォルト実装は以下のように改めた。

(defmethod operator_= (a (b clonable))
  (clone b))

 

これだと、デフォルトでは同じタイプのオブジェクト同士でもコピーが行なわれ、代入先のオブジェクトそのものが置き換えられてしまう。だが、そもそも clonable は値セマンティクスでの実装をするために利用するのだし、結果として clonable 派生を選択した場合は operator_= 総称関数のメソッドは作成することになる‥‥‥だからこれは別に問題にはならないだろう。

CL-STL が「コピーのセマンティクス」で動作するようになっているのは STL との整合性を考慮してのことなのだけれど、Common Lisp に慣れている人にとっては一番気に入らないところかもしれない。最近になって、「そこまで揃えなくてもいい」ような気がしてきた。でも、これは変えるとなると大手術だ。どうしたものかな。

 

コメント

このページにコメントする

 

このページのタグ

Page tag : STLとその移植

Page tag : Common Lisp

 

 


Copyright(C) 2005-2017 project-enigma.
Generated by CL-PREFAB.