プログラムと抽象化

気軽に抽象化、抽象化いってきたけれど、この言葉、難しいです。というのも、「抽象化と共通化は違う」というつぶやいたら、意外に面白いことになってしまったから。「抽象」を辞書で引くと、

事物や表象を、ある性質・共通性・本質に着目し、それを抽(ひ)き出して把握すること。その際、他の不要な性質を排除する作用(=捨象)をも伴うので、抽象と捨象とは同一作用の二側面を形づくる。

(大辞林 第二版)

多くのものから共通性を抜き出して概念をつくること.

三省堂 WebDictionary

個個別別の事柄などから、それらの範囲の全部のものに共通な要素を抜き出し、「およそ・・・と言われるものは そのようなものである」と頭の中でまとめ上げること。

(新明解 国語辞典 第四版)

複数の事象から共通のものを取り出す様を指しています。なんだか共通化と変わらない気がします。(ヤバいわ、わたし(^^; ) この訳語の元である abstraction とか abstract を英英辞典で引くと

ab・strac・tion

  1. [countable] a general idea about a type of situation, thing, or person rather than a specific example from real life
  1. 現実の特定の事例に基づかない、ある種の状況、物事、人についての概念。
abstraction | meaning of abstraction in Longman Dictionary of Contemporary English | LDOCE

ab・stract

  1. based on general ideas or principles rather than specific examples or real events [= theoretical]
  2. existing only as an idea or quality rather than as something real that you can see or touch [≠ concrete]
  1. 特定の例や現実の出来事よりも、概念や原則に基づいているもの (=理論)
  2. 見たり触れたりできる現実よりもむしろ、アイデアや性質 として存在するもの (≠具象)
abstract | meaning of abstract in Longman Dictionary of Contemporary English | LDOCE

手に触れられない何か、概念や原則に基づいた何か、といった意味があるようです。(ほっ)


では、プログラミングテクニックにおける抽象(abstraction)とはなんなのか。ダイクストラ先生の「構造化プログラミング論」の「抽象について」の項をみると、

1つのアルゴリズムとそれによるすべての計算を考えてみましょう. 計算から出発すると, アルゴリズムとは, その時点で扱われている特定の値から抽象したときに残るものです.“変数”の概念は, その時点の値から抽象したものを表します.

演算に名前をつけ, “それがどう働くか”という点を全く無視して, “それがどんな演算であるか”という点だけを知って, その演算をもちいることにかかわるもう 1つの抽象があります.

名前のついた演算が“どう働くか”を無視して, それを使用することと, 証明の仕方を無視して定理を使用することには、大きいアナロジーがあります. たとえ証明が, きわめて複雑でも, 使用するのに大変便利な定理であります.

なんかうまく抜き出せなかった...orz。まぁいいです。プログラミングにて抽象を行うということは、構造化エンティティ(メイヤー先生の言うところのモジュール。たとえばクラスとかサブルーチン)に プログラム片を封じ、その概念を示す名前をつけることです。

プログラミングでは、構造化という手段を用いて抽象化という目的を実現します。

なぜ抽象化を行うか

人間の脳はポンコツで、処理の難易度に関わらず単に規模が大きい(行数が多いetc)だけで、とたんに「理解」が出来なくなります。プログラムを抽象化をしたい動機は、ヘッポコな人間の脳の大規模への著しい脆弱さ加減をどうにかするため、見かけのプログラム規模を減らすことです。

プログラマは、抽象により作られた概念について、中の実装を気にしないことで使うことで、プログラムの見かけの規模を減らします。

なので、たとえそのコードがただ一度しか使われていなくても、あるコード規模以上になれば、抽象化する必要がありますし、中の実装を気にしなくても良い風に名前等を工夫する必要があります。

これを 単純ルール化 したものが、「関数の行数は○行以内に押さえる」とか「名前重要」とかになります。

通化となにが違うの?

コンピュータ資源が厳しかった昔なら「プログラムサイズを節約するため」とかあったのですが、今時それはないですね。同じコードを見かけたら共通化を試みるその動機は、プログラムに抽象の構造をもたらす切っ掛けだからです。

抽象の肝は分離にあります。先ほどの引用で、ある計算からアルゴリズムと変数を分離し、変数をパラメータとすることで、アルゴリズムという抽象を得る例がありました。共通のコードは、その差分を見ることで、何処を抽象として括り出せばいいかを比較的容易に見つけることができる、格好の材料です。

ただ、気をつけたいのは 必ず共通化=抽象化であるかというと、そうでは無いこと。

抽象において大事なのは、「○○とはどう動くモノか」ではなくて「○○とは何か」です。共通化はそれだけでは、「どう動くか」が同じであるものを、一つにまとめ上げるだけのこと。もしかしたら、たまたま同じなだけかもしれません。現状でたとえ同じ処理をしていたとしても、その本質(○○とは何か)が異なる処理を共通化してしまうことは、抽象化には値しません。

だから「共通化を通じて抽象化したいんだ」という意識をもつことが大事。

おまけ:オブジェクト指向でなぜ作るのか?

ダイクストラ先生の「構造化プログラミング」は、プログラムに 抽象の構造をもたらすことで、人間の知性の脆弱性を緩和し、それによりプログラムの品質を向上させることの重要さを敷衍しました。今や、構造化は常識です。

構造化プログラミングにおいて、構造化に用いる部品はサブルーチンであり、その性質上プログラムはツリー状の構造になること、データとアルゴリズムが分離してしまうこと、という二つの制約が科せられています。

オブジェクト指向プログラミングでは、構造化に用いる部品が クラス/オブジェクト になりました。それによって、抽象間の関係を 段階的詳細化に限定されずにすむようになりましたし、データとアルゴリズムの2つの側面を持つ 抽象部品を作ることも出来るようになりました。

また、この抽象構造の部品はOOPの用件として 必ず 第一級オブジェクトであるため、動的な抽象構造を構築することも容易になりました。(サブルーチン化において変数をアルゴリズムから濾しとったように)構造の一部をパラメータに濾し出せるので、よりパワフルに抽象できます。さらに 部品間の結びつきかた(=構造)に、型チェックを導入することが出来ます。抽象化 の道具として OOP は、かなり凄いですよね。

オブジェクト指向でなぜ作るのか?と問われれば、プログラムをよりパワフルに抽象化したいからで、そうすると何が良いのかについては、人間の脳力不足をドーピングできるため、{より楽に or より大きなプログラムの} プログラミングが出来るようになるからです。