オブジェクト指向で「参照透過性」がなくなる?新人エンジニアが知っておきたい「状態」の話

こんにちは。ゆうせいです。

オブジェクト指向の研修、順調ですか?クラスやインスタンスといった概念にも慣れてきた頃かもしれませんね。

今日は、そこから一歩進んで、オブジェクト指向の大きな特徴であり、ときには「弱点」とも言われる「参照透過性がない」という性質について、一緒に見ていきましょう。

「さんしょうとうかせい?」と、いきなり難しい言葉が出てきて戸惑ったかもしれません。大丈夫です。今日の記事を読み終わるころには、この言葉の意味と、なぜオブジェクト指向がそう呼ばれるのかが、しっかり理解できているはずですよ!

そもそも「参照透過性」ってなに?

まずは「参照透過性」(さんしょうとうかせい)という言葉から解説しますね。

すごく簡単に言ってしまうと、これは「計算の邪魔が入らない、ピュアな性質」のことです。

数学の計算は「参照透過」

一番わかりやすい例は、数学の計算です。

例えば、「$5 + 3$」という式があったとします。

この答えは、もちろん「$8$」ですよね。

この計算は、あなたが昨日やっても、今日やっても、あるいは100年後にやっても、必ず「$8$」になります。

また、「$5 + 3$」を計算したせいで、あなたの銀行残高が減ったり、明日の天気が変わったりすることも、絶対にありません。

このように、

  1. 同じ材料(入力)を使えば、いつ、誰が、どこで実行しても、必ず同じ結果(出力)が返ってくること。
  2. そして、計算の途中で「それ以外の余計なこと」を一切しないこと。(専門用語で「副作用がない」と言います)

この2つの条件を満たす性質を、「参照透過性がある」と呼びます。

プログラムの世界では、「同じ引数を渡せば、必ず同じ戻り値を返し、外部の状態を一切変更しない」関数などが、これにあたります。


オブジェクト指向は、なぜ「参照透過性がない」の?

では、本題です。なぜオブジェクト指向は「参照透過性がない」のでしょうか?

オブジェクトは「状態」を持っている

思い出してみてください。オブジェクト指向とは、「モノ」をモデル化する考え方でしたよね。そして、その「モノ」(オブジェクト)は、自分自身の「データ」を持っていました。

例えば、ゲームの「プレイヤー」オブジェクトを考えてみましょう。

このプレイヤーは、データとして「現在のHP(ヒットポイント)」を持っています。これを「状態」と呼びます。

仮に、今のHPが「100」だったとします。

ここで、あなたが「10のダメージを受ける」というメソッド(命令)を実行したら、どうなるでしょう?

player.takeDamage(10)

当然、プレイヤーのHPは「90」になりますね。

では、もう一度、まったく同じ命令を実行したら?

player.takeDamage(10)

今度は、HPが「90」から「80」になります。

同じ命令なのに、結果が違う!

ここに注目してください!

あなたは「$5 + 3$」のように、2回とも「まったく同じ命令」を実行しました。

しかし、1回目と2回目では、その「結果」(オブジェクトが置かれた状況)が異なっています。

さらに重要なのは、takeDamageメソッドが「プレイヤーのHPを書き換える」という「余計なこと(副作用)」をしている点です。

これは、先ほどの「参照透過性」のルールを、真っ向から破っていますよね。

  1. 同じ命令でも、実行するタイミング(その時のHPの状態)によって、その後の結果が変わる。
  2. オブジェクトの内部にある「状態(HP)」を、ガッツリ変更している(副作用がある)。

だから、オブジェクト指向は「参照透過性がない」と言われるのです。


参照透過性がないと、何が問題なの?

「でも、HPが変わるのは当たり前じゃない?」と思ったかもしれません。

その通りです!現実世界をモデル化しようとすると、「状態」が変わるのは自然なことです。

ただ、この「参照透過性がない」という性質は、プログラムを複雑にする要因にもなるのです。

デメリット:プログラムの予測が難しくなる

参照透過性がないということは、「そのメソッドを呼ぶまで、オブジェクトが今どんな状態か分からない」ということです。

  • 「あれ、この処理の前に、誰かがHPを回復させちゃったかも?」
  • 「このバグ、いつの間にかオブジェクトの状態が変わってたのが原因だ…」

このように、プログラムの動作を追うのが難しくなり、デバッグやテストが複雑になりがちです。

メリット:現実世界を直感的に表現できる

もちろん、悪いことばかりではありません。

私たちが暮らす現実世界は、まさに「状態」の変化であふれています。

(銀行口座の残高、ショッピングカートの中身、電車の座席の空き状況など)

オブジェクト指向は、そうした「時間ととも変化していくモノ」を、とても直感的にプログラム上で表現できる、優れた方法なんです。


新人エンジニアとして、どう学べばいい?

参照透過性がないからといって、オブジェクト指向がダメなわけでは、決してありません。大切なのは、その「特性」を理解してコーディングすることです。

これからの学習指針

  1. 「状態」を意識しようまず、あなたが書くクラスやメソッドが、「どの状態を」「いつ」「どのように」変更するのかを、常に意識するクセをつけましょう。状態の変化をむやみに増やさないことが、バグの少ないコードにつながります。
  2. 「副作用」を分離しようもし可能なら、「計算だけする純粋な部分」と「オブジェクトの状態を変更する部分」を、メソッド内で分けて書けないか考えてみてください。
  3. 「関数型プログラミング」に触れてみよう将来的に、もし余裕ができたら、「関数型プログラミング」という考え方にも触れてみると面白いですよ。こちらは、今日お話しした「参照透過性」を、ものすごく大事にするプログラミングスタイルです。オブジェクト指向とは対極にあるように見えますが、両方の良いところを知っておくと、あなたの引き出しは格段に増えます。

まとめ

今日は「参照透過性」という言葉と、オブジェクト指向が持つ「状態」という特徴について学びました。

専門用語が出てきて難しく感じたかもしれませんが、要は「オブジェクト指向は、内部データ(状態)が変わっていくから、数学みたいに単純じゃないよ」ということです。

この特性をしっかり理解して、変化に強い、読みやすいコードを書けるエンジニアを目指してくださいね。応援しています!

セイ・コンサルティング・グループの新人エンジニア研修のメニューへのリンク

投稿者プロフィール

山崎講師
山崎講師代表取締役
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。