前提条件(人)
-
静的型付け
に興味がある - 総称型(テンプレート型)とか言われても分かんない
- サンプル見てるけどいまいちピンと来ない
- 「Java、少し分かるよ」
合わない人
- 総称型をごっさ使ってる
- 妙な比喩は勘弁ね
- 細かい違いを許せない
本題
総称型、使ってますか。
総称型を使わない人は実体験が少ないので、
- 「やり方は書いてあるけど、具体的にどう使えば良いかイメージできない」
- 「よく分からない。何がおいしいの?」
こういう事があると思います。
ただ、総称型を使う基本的な理由はすごく単純です。
同じ処理を一つのコードにまとめて使いたいだけ
Java { name() { return ... } }
Julia { name() { return ... } } -> Lang { name() { return ... } }
TypeScript { name() { return ... } }
です。
言い換えると同じ処理なのに、型名が違うだけで、別々のコードとして作りたくない
です。保守が大変になるだけですからね。
「じゃあクラスを継承すればええやん!」
はい、確かに同じ処理を一つのコードにまとめるはクラス継承で簡単に可能でしょう。
しかし、やりたい事と考え方が一致しません。
総称型では
「クラスが持っている機能を、誰が使って良いか」
を決めます。そう、クラスの機能を使いたいのであって、
クラスの性質を受け継いだ別のクラスを作りたくはないのです。
あなたがレストランに行って、ご飯を頼みたいとしましょう。
その時にあなたが選ぶのは
- コックさんに依頼してご飯を受け取るために
- ウェイターの能力を受け継ぐために面接を受ける(クラスの継承)
- ウェイターにご飯を頼むための資格(お金)を持つ(総称型)
どちらを選ぶでしょうか。
今回あなたがレストランに行った目的は「ご飯を頼みたい」なので、総称型についての選択をするのが適切と考えられます。
そう、「ご飯を食べたい」だけであれば、「ウェイターにならなくて良い(クラス継承しなくてよい)」のです。
そもそもウェイターさんはレストランに既にいる(はず)なので、自分がウェイターさんになる(別のウェイターさんを増やす)事は目的からすると大げさな事なのです。
(目的次第でクラス継承の方が適切な場合もあるでしょう。「影響範囲を限定化したい」という目標も含み、継承に因る負債が増える可能性を覚悟するなら)
ただ、静的型付け
を使うのであれば、理由はこれだけではありません。
処理を使えるか使えないかを、型名でCompilerさんに気付いてほしい(エラーにしてほしい)
class Family<? extends Lang> {}
Family<Java>
Family<Julia>
Family<TypeScript>
Family<OreOre> -> Compilerさん「誰やねんOreOreて!Langさんとこの子ちゃうがな!」-> コンパイルエラー
となります。
同じ処理を一つのコードにまとめたいだけなら、「void*
型を使っちゃえ!(何でもありの型の例)」というだけで終了です。
静的型付け
を使えるのならば、合ってるか間違ってるかをコンパイル時に知りたいのです。
(総称型を使わない場合、実行時に合ってるか間違ってるかを知れますが、それでは静的型付け
の持ち腐れになります)
ただ気を付けなければならないのは、静的型付け
は論理的な間違いを指摘してくれるけど、意味的な間違いは指摘してくれないという事です。
よくあるソクラテスのネタを使いますと、
ソクラテスは人である
人は死ぬ
ゆえにソクラテスは(人だから)死ぬ
があります。これを
ソクラテスはサイヤ人である
サイヤ人は死ぬ
ゆえにソクラテスは(サイヤ人だから)死ぬ
というピンクの人(時々ゴールド)が言いそうな三段論法も、「合っている」とCompilerさんは結論します。
でも(多分)ソクラテスはサイヤ人じゃなかったと思うので、
ソクラテスは「サイヤ人だから」という理由では死にません。
なので、静的型付け
に因るCompilerさんの検査は論理的には合ってるけども、意味(意図)の保証ではないという事です。
当たり前と怒られそうですけども、これを意識するかしないかでテストがどれだけ重要かの認識力が変わってきます。静的型付け
、総称型
も結局は「便利にするだけの道具」に過ぎませんので、本来の目的を見失わないようにご留意下さい。
終わりに
グダァッとポエムの如く書きました。
コメントには(能力不足により)返信できませんのでご了承下さい。