オブジェクト共有

今日、書こうと思っていた内容を、見事にid:lethevertさんによってid:succeed:20060330のコメントで書かれてしまった。
もともと、id:lethevert:20060328:p3を読んで、この方が考えている内容が非常に近いことに気づき、そのことについてもコメントしようと思っていた矢先だったので、驚くと同時にうれしく思っています。
さて、その内容。単一のオブジェクトを複数の変数が参照していると言う構造があるとします。このときに、この共有されているオブジェクトの中身を変更すると言う処理を行った場合、その変更が他のオブジェクトの参照元に伝播されるべきか否か、という問題です。
この問題は一概には言えません。例えば、そのオブジェクトがInteger等のような本質的にプリミティブなものであれば、通常は参照元に伝播されてはいけません。
しかしながら、例えば有向グラフがあったとして、Nodeをオブジェクトとして表現し、EdgeはNodeからNodeへのポインタとして表現されているとします。イメージとしては、Nodeクラスはこんな感じ。

class Node{
    public List edge;
}

このような場合で、Nodeの位置が変更することがあったとします。その場合、対象となるNodeに対してmoveというメソッドを介して変更をすれば、そこにつながっている他のNodeも変更しなくてはいけません。じゃあ、これはどうすればいいのだろうか、と。
その場合、二つの方法が考えられます。一つは、それら全てのNodeを管理するManagerを用意して、そのManagerがNodeに対するメッセージを一旦全て受け取り、オブジェクトに対する変更があれば、変更されたオブジェクト集合を持つManagerを新しくnewして返す、という方法です。この方法は、確かに破壊的代入を行わずに実装することが出来ます。
もう一つは、素直に破壊的代入を認めると言う方針です。少なくともこの場合であれば破壊的代入は有効に作用するでしょう。つまり、破壊的代入の禁止と言うのは、当然ながらケースによっては良い方向に作用しないと言うことです。
では、そのようなケースをどのように場合分けしてやればよいのか、あるいは言語によって規制をしてやればいいのか、という問題があります。破壊的代入を悪とするのであれば、基本的に全ての変数をimmutableにしておいて、必要な部分(すなわち共有される部分)のみを破壊的代入をOKにしてやるという手段がよいのではないかと思います。つまりはOcamlの方針です。

こんな感じで考えてみたのですが、どうなんでしょうね。結論とするのには当然まだ早いのですが。