るびま読書会#2

先日、私が主宰で るびま読書会をひらきました。

そのときの議論になった項目についていくつか記します。

ディープコピーとシャロウコピーについて

Ruby の Marsharl が出てきたので、「それはディープコピーを行いたいときに使います」と発言したあたりから議論が発展しました。

ディープコピーというのはあるオブジェクトが保持する先のオブジェクトまでコピーすることです。反対の意味に使われる言葉は、シャロウコピーで、この場合は 参照をコピーすることになり、オブジェクト間で共通のオブジェクトを参照することになります。ディープコピーでは、オブジェクト間で共通のオブジェクトを参照することはありません。


ディープコピーをいつ使うべきかということは多くの初学者のプログラマが悩む問題のようです。

まず、簡単に私の意見をここで書きます。

まず、ディープコピー、シャロウコピーをいつ使うかというのは正しい問いではありません。

正しい問いは、いつ破壊的メソッドを使い、いつは使うべきではないかということです。

説明しましょう。

ディープコピーを使わなければならない状況というのは、共通のオブジェクトを参照しているとまずい状況です。共通のオブジェクトを参照するとまずい状況というのは、ある処理で変更した結果、本来は期待していないのにその変更した値を参照してしまうという場合です。
そして、2つのオブジェクト間でその変更した値を参照してしまうというのは破壊的メソッドを使う場合に起こります。

逆に言うと、破壊的メソッドを使わなければ、思わぬ副作用で、オブジェクトの値が変化していることはありませんし、それを避けるためにディープコピーを保持するような必要もありません。

では、いつ破壊的メソッドを使うべきなのでしょうか?

答えは簡単です。破壊的メソッドを使うという判断はそのプロジェクトのかなり完成が近づいたときまで遅延するべきです。
私の意見では、少なくとも完全に動くプログラムを作成し、そしてそのプログラムの動作が遅いという理由で不便さを感じていると判断して初めて破壊的メソッドを使うことを検討するべきです。

なぜなら、破壊的メソッドを使うと、先に説明したような現象によって、バグが生じやすくなるからです。破壊的メソッドを決して使わないようなコーディングスタイルであれば、そのようなバグを避けた開発を行うことができます。

開発の初期では仕様どおり動くプログラムを作成することに専念するべきです。アルゴリズムレベルでは高速なものを検討するべきです。しかしながら破壊的メソッドを使うかどうかというのは比較的簡単な修正であり、その修正はいつでもできます。

しかしながら、シャロウコピーと破壊的メソッドによる副作用によるバグは見つけにくく、そのデバッグは手間取ることが多くなります。

そのため、破壊的メソッドを使うようにするのは、高速化のための最後のブラッシュアップのときにとっておき、最初は正しく動作することだけを念頭に開発するべきです。

このようにしておけば、ディープコピーを用いることはそもそも必要なくなります。

実際私はプログラミングしているときにディープコピーを必要としたことはほとんどありません。

他に、その会では、継承と delegate などについても話しました。

そのあたりについてはまたの機会に書こうと思います。