【注意】下記文章には私感が入っています。
**正解はありません。**どちらも正しいです。
これはmutable(変更可能)とimmutable(変更不可)の終わりなき戦いです。
###mutable…それは命令型プログラミング
C++由来のオブジェクト指向は構造体の拡張でした。元々はデータをまとめた構造体ですので、その使い方の考え方も変わりませんでした。オブジェクトは基本的にmutableであり、メソッド(言語によってはメンバー関数とも呼ばれる)によってオブジェクト内のデータ、つまりインスタンス変数(言語によってはメンバー変数、フィールド変数とも呼ばれる)として保存されている何かを変更するというものでした。
この考え方はCの時から使われており、命令型プログラミングと言われるものです。命令型プログラミングはデータ(オブジェクト)を命令(メソッド)で随時変化されながら、計算を行う手法です。この方法はオブジェクトの生成という新たなデータ領域を確保する必要が無い等の理由により、次のような利点がありました。
- メモリの値の書き換えのみのため、高速。
- オブジェクトの生成がないため、GCが無い言語でもメモリ管理が不要。
- 命令型プログラミングになれたプログラマーがオブジェクト指向に入門しやすい。
- 現実世界の物で例えたオブジェクト指向の説明がしやすくなり、直感的。
Cを拡張したC++を始め、メジャーなオブジェクト指向言語、例えばPython、Ruby、Java、JavaScript、C#等はこの命令型プログラミングによるオブジェクト指向を取り入れました。Javaの流行やGoFによるデザインパターンなどオブジェクト指向の研究が進んでも、mutableなオブジェクトであることが前提であり、メソッドによってオブジェクトを変化させていくという考え主流でした。
しかし、この方法には欠点がありました。
- マルチスレッド環境において、別スレッドによる変更を考慮しなければならない。スレッドセーフなオブジェクトを作るにはオブジェクトの動作定義部分、つまりそのクラスにおいてロックや同期を実装しておく必要がある。マルチプロセス、マルチノードではさらに複雑なロックや同期を考える必要がある。
- オブジェクトの状態別にテストを行う必要があるため、ユニットテストが複雑になる。その分、テスト漏れが発生する確率も高くなる。
現代において、単体の速度より並列処理によるスケールアウトが可能かが重要視されています。マルチスレッドはもちろんのこと、マルチプロセス、マルチノードでも動作できるかは大規模システムでは重要なことです。また、テスト駆動開発等、テストはますます重要視されており、それが書きやすいか書きにくいかは重要なテーマです。そのため、命令型プログラミングだけでは限界が来つつありました。
これらを解決するために復活したのが関数型プログラミングです。
###immutable…それは関数型プログラミング
いきなり関数型プログラミングという言葉が出てきましたが、なんじゃらほいという感じでしょう。しかし、immutableなオブジェクトを語る上で関数型プログラミングという手法は避けて通れません。
関数型プログラミングの歴史は古く、Cよりも古いLISPが最初と言われています。LISPは優れた言語でしたが、メインのアプリケーションに使われることは少ない物でした。その後も、Haskell、Erlang、OCamlなど関数型プログラミングに適した関数型言語が作られますが、メジャーに立つことはありませんでした。関数型プログラミングは一時期人々に忘れ去られた存在だったのです。しかし、ひっそりと時を伺うようにその進化は続けられていました。
そして、最近になって関数型プログラミングは大きく注目を浴びるようになりました。それは、命令型プログラミングの限界を解決するのに非常に適していたからです。そう、先に挙げた二つの欠点を関数型プログラミングでは克服していたのです。それは、オブジェクトをすべてimmutableとして扱うことで、並列処理におけるロックや同期を不要とし、状態別のテストも不要にできたからです。
そう、関数型プログラミングでは、基本的に全てがimmutableなオブジェクトです。一度生成されたオブジェクトが変更されることはありません。でも、変更不可だと今までの方法が使えなくなりますよね?そこで、それを簡単に扱えるように、ラムダ式と高階関数、再帰、カリー化と部分適用、パターンマッチ、モナドなどの方法が開発され、(関数型プログラミングに慣れている人にとっては)簡単にデータを処理できるようにしたのが関数型プログラミングなのです。逆に言うと、immutableなオブジェクトとして扱うなら関数型プログラミングを使わないと難しいと言うことです。
関数型プログラミングの考え方は、技術の最先端の人達にすぐに取り入れられました。例えば、オブジェクト指向と関数型プログラミングを融合したScalaが作られました。Python、Ruby、C#など本来は命令型プログラミングのオブジェクト指向でも、関数型プログラミングがしやすくなる機能を取り入れ、(部分的に)関数型プログラミングとして書くことも可能にしました。現代において関数型プログラミングは主流技術の一つであり、全体、もしくは、部分的にでも取り入れないと安全な大規模システムは難しくなると考えられます。
もちろん欠点があります。それは命令型プログラミングの全く逆です。オブジェクト生成によるオーバーヘッド、GC必須、関数型プログラミングを知らないと難しい、などなどです。
###結局どちらがいいのか?
一長一短です。並列処理やテストに強いのはimmutableの方でしょう。より安全にプログラミングをすることができます。しかし、速度面ではmutableに劣ります。オブジェクトの生成を省略できるような最適化ができないと毎回オブジェクトを生成するコストはバカになりません。また、ファイルオブジェクトのように副作用と状態変化が前提のものはimmutableで作ること自体が不可能です(モナドを使えばできますが、ここでは説明しません)。
現代におけるオブジェクト指向はmutableとimmutable、命令型プログラミングと関数型プログラミングをいいとこ取りで組合せながら行うのが主流になってくると個人的には思っています。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。