「シコウ」を語る Advent Calendar 2021 1日目の記事です。
はじめに
プログラミングパラダイムは、プログラマにプログラムの見方を与えるものと言える。
オブジェクト指向プログラミング、関数型プログラミングなどなど、
プログラムパラダイムの記事は好きですか?
私は、 苦手ですが、好き です。
苦手な理由は、 バズワードの要素があり、定義が曖昧1 なところ。
好きな理由は、 色々な考え方に触れ、嗜好が分かる ところ。
例えば、今年話題になった、プログラミング言語を、
手続き型と関数型、静的型付けと動的型付けで分類する以下の記事
プログラミングパラダイム(事象)の度合いを 主観で決めている、という点で苦手 ですが、
「非エンジニアにもわかりやすく理解をしてもらうため」に 特徴の俯瞰をしている、という点 では好きです。
さて、突然ですが、私は Ruby と TypeScript が好きです。
(実はTypeScriptについては、始めるまでは良い印象を持っていませんでしたが。)
では、私は どのようなプログラムの見方 、つまり、
どのようなプログラミングパラダイムを好んでいる のでしょうか?
残念ながら、 適切なプログラミングパラダイムを示す単語はなさそう でした。
なければ、作って、説明しよう
というのが、本ポエムの動機です。
本記事はポエムです。 本記事はオブジェクト指向プログラミング(OOP) の知識/経験を前提とします。 また、構造型指向(SOP)や、公称型指向(NOP)は、 本ポエム内の造語であり、一般的な単語ではありません。
構造型指向(SOP) と 公称型指向(NOP)
構造型指向プログラミング (SOP) : Structural typing Oriented Programming
公称型指向プログラミング (NOP) : Nominal typing Oriented Programming
まずは、これらの定義を説明します。
Nominal typing は、聞きなれないという人も多いでしょう。
実は筆者も、そうでした。筆者は、Nominal typing | TypeScript Deep Diveの日本語版 を読んで初めて意識しました。
Nominal typing を 公称型 として @suin さんが関連した、分かりやすい記事を書いてくれています。
Nominal typing を聞いたことがない人は、まずは、こちらの記事をよんでください。
なお、 英語版wikipedia には、 nominal type system の記事があります。
nominal or nominative type system (or name-based type system)
名前ベースの型システム とも言えますが、本記事では、 公称型 で統一します。
これは、継承などで型同士の関係が明示的に定義されることを前提とした型システムと言えるでしょう。
Nominal type systems contrast with structural type systems,
また、記事中には、対比として structural type system の記事へのリンクがあります。
structural type system (or property-based type system)
プロパティ(属性)ベースの型システム とも言えますが、本記事では、 構造型 で統一します。
これは、型の構造(属性の構成)に着目した型システムと言えるでしょう。
つまり、本記事中では
型の構造(属性の構成) に着目する手法を、 構造型指向(SOP)
(継承など)定義された関係 に着目する手法を、 公称型指向(NOP)
とします。
subtyping ≒ (型の)互換性
さて、TypeScriptの普及でよく耳にするようになった、
structural subtyping (構造的部分型) という単語の
subtyping とはなんでしょうか?
筆者は英語に疎いのですが、
typing "型付け" が、 type "型" の動名詞であるように、
subtypingは、subtypeの動名詞 でしょう。
(typing は、 dynamic typing(動的型付け) や、 static typing(静的型付け) などで使われています。)
では、次に名詞 の subtype について考えてみます。
subtypes は、 weblioで調べる と、ライフサイエンス辞書において、
サブタイプ, 亜型, 亜類型
という意味が掲載されています。もともとは、生物学における分類のための単語と考えられます。
サブタイプを コトバンクで調べる と栄養・生化学辞典において、
特定の機能をもつ分子(ホルモンレセプターなど)を,性質に従っていくつかの型に分類する場合,さらにいくつかの項目について細分することがある.この細分されたそれぞれの型.
という説明が記載されています。
筆者は、一般的なサブタイプの認識としては、この説明が分かりやすいと感じました。
では、プログラミングにおける subtype はどうでしょうか?
プログラミングにおいては、 subtype は、 派生型 や 部分型 と訳されます。
派生型 と 部分型 は同一のものを指していると考えて問題ない1ですが、
与える印象は異なります。
例えば OOPでは、以下の様に使い分けられているようにも感じます。
派生型 : extend(継承) を利用するとき
部分型 : ポリモーフィズム(多態性) を利用するとき
これは、 subtype が、プログラミングにおいて、
実装の再利用 時と、 型の分類 時の2つのシーンで使われるためです。
subtyping は、後者、型の分類時のシーンでよく使われているように感じます。
そのため、本記事での、 subtyping は (型の)互換性 と解釈します。
(ただし、structural subtyping については、 慣例として構造的部分型 とします。)
なお、筆者は subtyping に関連したキーワードとして、
Cast , Interface , Type assetion 等の単語を連想します。
これらのキーワードの方が、プログラミングに直接関連しているため、
馴染みやすい人も多いでしょう。
なお、subtype について、実装の再利用 と 型の分類 を 区別して考えることは重要 です。
本記事の、SOP/NOP については、後者 型の分類 のみが議論の対象となります。
なお、以下のように、type/typing を使う場合と、 subtyping を使う場合があります。
- structural type(構造型)
- structural type system(構造型システム)
- structural typing(構造的型付け)
- structural subtyping(構造的部分型)
本記事中では、個々のプログラミング言語など具体的な場合は、より明確な subtyping を、
指向(oriented) 、設計や考え方など抽象的な場合は、 type/typing を使用しますが、
使い分けに重要な意味はありません 。
ダックタイピング(duck typing) について
構造的部分型 (structural subtyping) に似た概念として、
ダックタイピング(duck typing) があります。
ある鳥が鴨のように見え、鴨のように泳ぎ、鴨のように鳴くならば、それはたぶん鴨である。2
ダックタイピングは、上記引用で説明される、ダック・テスト(duck test)に由来します。
特定のメソッド(またはメソッド群)を実装したオブジェクトが必要な場合に、与えられたオブジェクトが必要とする メソッドのすべてを実装しているのであれば 、その実装方法がどのようなものであれ(型宣言の有無、継承の経路などに関係なく)、 それで良い という考え方である。2
『メソッドの実装』 は、 プロパティ(属性)の有無 と 同じ意味 であり、
『それで良い』 は、 互換性がある と 同じ意味 と解釈できます。
では、 構造的部分型 と ダックタイピング は同じものなのでしょうか?
かの matz も 5年前につぶやいているようです。
では、その謎を解き明かすべく、英語版wikipediaのgoogle翻訳結果を参照してみましょう。
ダックタイピングは、構造型タイピングと似ていますが、異なります。 構造型は静的型付けシステム であり、型の構造によって型の互換性と同等性を判断しますが、 ダックタイピングは動的 であり、実行時にアクセスされる型の構造の部分のみによって型の互換性を判断します。3
つまり、プロパティ(属性)で互換性判定を行う点では同じだが、以下の様に区別されるようです。
- 静的型付け 、つまり、 コンパイル時 の互換性判定が、 構造的部分型
- 動的型付け 、つまり、 実行時での互換性判定 が、 ダックタイピング
しかしながら、筆者はこの分け方に、 完全には賛同しかねます 。
なぜなら、ダックタイピング由来の、ダックテストの語感からは、
公称型(アヒルの判定を、遺伝子などの分析で分類するイメージ)に対する、
構造型(アヒルの判定を、外見や振る舞いで分類するイメージ)の特徴を連想し、
そこに、 静的型付け か 動的型付け かどうかの意味合いは存在しない ためです。
(ダックタイピングの「振る舞い」という単語から、少しだけ動的型付けを連想しますが。)
ダックタイピングに、動的型付け か 静的型付け かの意味合いが含まれるように感じるのは、
当初の議論において比較対象となりやすい 主流の プログラミング言語 が、
「静的型付け 、かつ、 公称型の互換性判定」のプログラミング言語と
「動的型付け 、かつ、 構造型の互換性判定」のプログラミング言語、
の2種類4 だったことも一因でしょう。
(また、それに伴い、ダックタイピングに、動的型付けのネガティブな特徴のイメージも5付随したため、それを避けるために、構造的部分型を用いることも多いと感じています。)
実際に、 TypeScript Deep Dive 日本語版 では、構造的な型(Structural type system) に対する説明として、以下の様に記載されています。
TypeScriptは、JavaScript 開発者に対する認知的な負荷をなるべく小さくするため、 構造的な型(structural type) を採用しています。これが意味することは、 ダックタイピング(duck typing)が第一級(言語レベルでサポートされている)のもの である、ということです。
この記述からは、 構造的部分型がダックタイピングの派生 であり、
ダックタイピングは構造的部分型を含むもの であるように読み取れます。
この例の他にも、例えば、静的型付け言語である、 go で ダックタイピング の記事を調べると、
ダックタイピングに対しての解釈が異なる記事を、たくさん見つけることができるでしょう。
以上より、筆者の見解としては、ダックタイピング と 構造的部分型 は、
広義では同じ だが、 狭義では異なる と考えています。
つづく
語りまで入れませんでしたが つづきは、「シコウ」を語る Advent Calendar 2021 22日目の記事として、構造型指向(SOP) か 公称型指向(NOP) か、それを知りたい ~ 型と設計 ~ を投稿予定です。6
「シコウ」を語る Advent Calendar 2021 は、ほとんど埋まっていない まだまだ枠がありますので、語りたいことがある人は、是非参加してください!
-
とはいえ、プログラミング全般に関連した話題については、話者や時代により具体的なプログラミング言語のバックボーンが異なるため、定義が曖昧になることは避けられないとも考えています。 ↩
-
https://ja.m.wikipedia.org/wiki/%E3%83%80%E3%83%83%E3%82%AF%E3%83%BB%E3%83%86%E3%82%B9%E3%83%88 ↩
-
ここでは、C, Java に対する、python, php ruby を想定 ↩
-
例えば、typoしても動く(実行時にしか気づかない)など ↩
-
実はずいぶん前の書きかけの記事の供養で、この続きは投稿できるレベルの内容が書けていませんでした。22日までに頑張って書こうと思います。 ↩