目次
- 型制約がある環境のありがたさ
- データ生成の流れを作りやすくなる
- チェックが通れば安全が確保しやすくなる
- 自分でコードを設計して制御できるのがいい!
型制約がある環境のありがたさ
型制約があると、データの記述が書きやすくなります。まず、このデータ記述の基礎にある考えの型システムから説明していきます。
型システムの型検査は、コードの型を見て使われている型が正しいのかをチェックしてくれます。整数しか入らない部分に整数が入れられていないか、文字列しか入らないところに文字列しか入れられていないかを見ていきます。
下記は使う方を誤ったRubyで書かれたコードとTypeScriptのコードになります。
def addNumbers(a, b) a + b end # 正常に動く addNumbers(5, 10) # 実行時エラーが吐かれる addNumbers(5, "10")
function addNumbers(a: number, b: number): number { return a + b; } const result = addNumbers(5, 10); console.log(result); const result = addNumbers(5, "10"); // 型エラー: 文字列型の引数が期待される数値型に代入されています console.log(result);
上記は足し算を実装したコードです。Rubyは1回目のaddNumberのコードは正常に動くのですが、2回目のaddNumberのコードでエラーが吐かれます。
TypeScriptもエラーが吐かれますが、Rubyと違うのはJavaScriptにコンパイルする前にエラーが吐かれます。
動的型付け言語だと、実行時に初めてエラーが出る仕組みになっています。これは、コードを読み込んで、実行するときにRubyの方で解釈をして機械に命令を実行する仕組みにしています。
型システムの型検査はコンパイル前にコンパイルするコードの型をすべてチェックします。コードを実行する前に型の違いで動くことをコンパイル時にチェックできれば実行する手前で検知することができます。
Rubyに比べるとTypeScriptの方、つまり動的型付け言語よりも静的型付け言語のほうが作りづらいように見えます。ですが、静的型付け言語にもコーダーにとって恩恵があります。
恩恵1: データ生成の流れを作りやすくなる
データの動きを自分で制御できるのはコーダーにとって大きな恩恵です。
先程の例文のコードでは数字の型検査をしていて単純なコードになっていますが、これが自分の作った型や、特定のハッシュの形でコーディングをしたい場合は動的型付けだけだと制御しづらいです。
例えば、{"total": number, "count": number}
の型を使ってtotal×countの計算をしてもらうコードを作ったとしましょう。
def total_count_mult(x) x[:total] * x[:count] end # 動作する puts total_count_mult({"total": 20, "count": 2}) # 動作する puts total_count_mult({"total": 20, "count": 2, "hello": 10})
Rubyコード
function total_count_mult(x: {"total": number, "count": number}): number { return x["total"] * x["count"] } // 動作する total_count_mult({"total": 10, "count": 20}) // エラーになる total_count_mult({"total": 10, "count": 20, "hello": 10})
TypeScriptコード
Rubyでは"hello"というキーを追加しても動きますが、TypeScriptではエラーが起こります。一見すると、TypeScriptのほうが使いづらいし、同じようなデータの型でなんでエラーが起こるかと見えるでしょう。
ですが、total_count_multを作った人は{"total": number, "count": number}
という引数で設計をしているので、使う側の{"total": 20, "count": 2, "hello": 10}
は設計書の意図とは違うんです。
自作のhash型を入れると返り値はnumberが帰って来るという意図をきちんと伝えてその上で実行することで、データの流れが見やすくなります。こうすることで、作っている最中にエラーが起こってもどこでバグが起こっているかが見やすくなります。
恩恵2: チェックが通れば安全が確保しやすくなる
更にデータのコードの型が正しいと証明されることで、バグの発生原因を減らすことができます。
バグの発生の原因の一つに、意図しない使い方をされるケースがあります。数値型をいれなければならないところに文字列を入れたらバグが起こります。恩恵1で出したtotal_count_multだと型が違う場合にエラーが起こるのは、使ってほしい使い方をしていないのがエラーの原因になっています。
型をチェックさせるコンパイラーが通ったということはコンパイラーが定めた静的型付けのルールに則ったコードになっていることの証明になります。これは、もとの原理は違うにしても、linterを通したらpushできる仕組みに似ています。
コンパイラーが通れば、少なくとも型に依存した処理はエラーがなく本番運用したとしても、バグを起こす可能性を減らすことができます。
恩恵3: 自分でコードを設計して制御できるのがいい!
自分のコードを設計をして、設計通りに制御できることで、コンピューターを思い通りに動かしやすくします。
型の生成方法を自分で制御できるということは、データ型にあったアルゴリズムを作りやすくなります。アルゴリズムは基本的にデータ構造と手順が一対多になる構造になっています。例えば、ソートアルゴリズムも基本的に配列と特定の整理する手順が一対一になっています。
ソートアルゴリズムを実現するために、データ構造を定めてデータ構造にあった手順を人間が作らないといけないです。このデータ構造と手順を人間側ですべて設計を決定することでコンピューター側はデータの型が正しいかを検査し、それ通ったコードを実行します。
この方法は、初学者からは面倒だし、挫折する原因になり一見そんな手間をかける必要がないように見えます。しかし、人間はミスをする生き物です。そのミスを実行時に発見するのと、ミスを発生する前に見つけるのとは、実行時に修正するよりも発見してもらったほうが仕様を覚えていれば直しやすく品質も保てます。
すべてを人間側で設計、実装を担うことで機械は静的型付けのルールに則った方法を取ることで正確に実行することができます。もちろん、コンピューター科学の基礎を身に着けていれば、もっと品質を上げることができます。
また、型システムの逃げ道に逃げずに作り込むことで長い目で見れば保守しやすいコードを作りやすくなります。コードが途中で粗悪なコードに置き換わったとしても型システム関わるものだったら止めることができます。また、TypeScriptのany, Rustのunsafeのような逃げ道を使うにしても、それを使う意図を常に問われればコードの品質も上げることができます。
コンピュータを自分が思ったとおりに作れるようにする
どんな制作物でも自分の思ったとおりに作る、動かすことが大前提になります。コンピューターならなおさら自分のコントロール下に置く必要があります。
型システムは制御を過去の知見をもとに整理されたシステムです。C言語の時の静的型付けとは毛色は違いますが、厳密な静的型付けにすれば少なくとも型によるバグに悩まされることがすくなくなるはずです。
なにかを作るときに一番ストレスになるのは、作っているものが自分の制御下に置かれないことだ。ここでいう制御下に置かれない状態とは、厳密に自分の作ったものが自分が思った通りに動かないことを指します。これは整数で動くはずのコードが文字列でも動いてしまった時も同様です。
意図しない事態でも動くことが制御されていないということになるかは、「自分が想定した動きをしていない」からです。
整数で動くはずのコードが文字列でも動くことは、コードを使っている側から見れば文字列も正常であると認識してしまう。すると、テストをしていたのが整数だけだったのに文字列も追記した途端にテストがされていない状態になります。
これが恐ろしいのは、いつの間にか文字列も正しいということが広がって、文字列も許容することになり、テストする範囲が広がってしまいます。自分が設計したものとは違うコードが自分が知らない間に作られてします。
動的型付け言語では言語上これが許されます。これにはメリットがあります。作っている本人が文字列でも使えるように考えているのならば作る手間は減ります。動的型付けは実行するときに型が決定するので、それを踏まえれば引数が文字列の場合でも、ハッシュ型でも使えると想定していれば問題はありません。
しかし、これは非常に高度なプログラミング能力を必要とされます。型を作るパターンの把握とそこで使われるメソッドの把握、アプリケーション全体の把握を必要とします。高度なプログラミング能力がないと正確に作ることを困難にします。
静的型付け言語の型システムを使えれば、プログラムを作る体験を向上してくれるでしょう。少なくとも、自身が型システムについて理解を深めれば技術が向上しやすくなるはずです。