読者です 読者をやめる 読者になる 読者になる

エンジニアの箱

サーバ構築とか、Ciscoルータの設定とか、コーディングに関してのなにがしを書きます。

型宣言なし言語への偏見をなんとかしたい

なんというか、型宣言のない言語への偏見がすごいので何とかしたい。

そもそもデータ型の存在意義とは

データ型の存在意義というのは、「その変数に対する抽象化」であるといえます。例を交えましょう。

a = 255

これはaという変数に255を代入しています。ということは、aという変数のデータ型はintであることが推測できます。

ではこれは?

a = b

分かりませんね。困りました。

という状態を防ぐのが型宣言です。データ型というのはその変数が取りうる値の性質をグループ化して表現することで、「具体的に何が入るかは分からない。ただ俺にはintしか入らねぇぜ!」という状態を作れます。そしてそれを事前に宣言するのが型宣言です。
こうすることで、intをbooleanと間違えて if (a)などとしなくて済みます。なぜならコンパイル時点ではじいてくれるためです。

型宣言がある場合の例

型宣言があることによるメリット

例えば

int a = 0;

としてあればaにはintしか入らないため、「この変数には文字列が入っているのか?それとも浮動小数点数か?」といったチェックを自動的にしてくれるようになります。これは潜在的なバグを引き起こしにくくなることを意味します。例えば、

a = 1;
b = 2;

とあったとして、a + bは当然3になるはずです。しかし何かのはずみでデータ型がstringになっていたとすると、a + bは12になってしまいます。仮にこの計算結果をどこかで使っていると、計算が合わなくなりバグを引き起こします。がしかし文法的に間違っているわけではないのでコンパイルエラーにはなりませんし、例外ログにも残りません。トレースの難易度が上がります。
そこで、

int a = 1;
int b = 2;

としておくことで、a + bが3になることを担保できます。型宣言にはこういった安全装置の役割もあるのです。

型宣言があることによるデメリット

一方、型宣言があることによってデメリットもあります。例えば、こんなもの。

double pi = 3.14;
int x = pi;

これでは、xに代入される値は3となってしまい、期待通りの結果となりません。また、型がオブジェクトの場合は少々やっかいなこともあります。例えば、これ。

List<int> list = [0, 2, 4, 6];

Javaにおいてこの記法は許されません。同等のことをしようと思うとこうしないといけません。

List<int> list = new ArrayList<int>(Arrays.asList(0, 2, 4));

いささか冗長ですね。そう、型宣言は自動でエラー検出をする代わりに冗長なのです。これは、プログラミングを熟練すればするほど鬱陶しく感じることでしょう。

型宣言がない場合の例

型宣言がないことによるメリット

さてはて、型宣言がない場合はどうでしょう。同じ例を取ります。

pi = 3.14;
x = pi;

xには正確に3.14が代入されます。これは期待通りでしょう。さらに、型がオブジェクトでも厄介なことにはなりません。

list = [0, 2, 4, 6];

Pythonであれば、これはlistオブジェクトとして解釈されます。制約はありません。 つまり、見たまま・やったままを実行してくれます。これは楽です。こちらが明示的に入れ物を変化させることなく入れ物を適切に変更してくれるためです。入れ物を変更するのは大変です。時にはデータ構造をも変更しなければならないほどです。これは純粋なロジックを記述するとき邪魔になります。なぜならば、ロジックを考えることに集中できなくなるからです。本質は入れ物の中に何が入るかなのに、どの入れ物を用意するかで多くの時間を消費することになるからです。

型宣言がないことによるデメリット

a = 1;
b = 2;

とあったとして、a + bは当然3になるはずです。しかしプログラマのミスでうっかり

a = "1";
b = 2;

などとしてしまっていると、a + bの結果が予測できなくなります。もし暗黙的にデータ型を変更されでもしてしまったら、a + bが3になるか12になるか、動かすまで検討がつきません(もしくはよほど言語仕様に詳しくない限り)。ただしPythonは異なるデータ型同士の足し算はエラーとしてくれます。ですので、どちらの結果になるか分からないではなく、実行時エラーとして知らせてくれるためこちらが考えるコストは幾分か少なくなります。

結論

型宣言がない場合のデメリット、なんだか微妙ですね。そもそも動かす前のエラーは、IDEが検知してくれない限り我々は知る由もありません(コンパイル時に知らせてくれるじゃないか!というかもしれませんが、インタプリタ型にとってはコンパイル=実行であるため、強く型付けされていれば大差ないのです)。そう考えると、残念ながら型宣言がないことについて、コーディング時はあまりデメリットはないということです。むしろ型変換を行なうロジックを組まなくて済むため、本質に集中できることでしょう。ただし残念ながら実行速度はデータ型があった方が上です。また、PHPJavaScriptなどの弱い型付けの場合はこの限りにはありません 。多少データ型がおかしくても実行されてしまうため、やっかいなバグを生みやすくなるでしょう。つまり、型宣言があるかないかではなく強い型付けなのか弱い型付けなのかで議論した方がよい ということになります。特にC#などは型宣言をしなくとも(正確にはvarなどで記述する)、型推論をしてくるため幾分か楽であると言えるでしょう。強い型付けの場合は、型宣言など行なわなくともほとんどの場合不整合が起きないです。
ということで、これからは
強い型付けor弱い型付け
で議論をしたいなぁという結論でした。ちなみに私は型宣言は足かせでしかないと思っています。コンパイル時にエラーがみたいな話は聞きあきました。動かせばわかることですし、仮に動かすのが難しいのであるとするとそれはそれで大問題です。もしどうしても性質上動かすのが難しいということであれば、テストコードを書けばよいのです。テストコード、書きましょう。