Dartの素晴らしさがまだ分からない無知無識の者が、Dartの型システムについて深刻な誤解をしている。ここでは、Dartの型システムであるOptional Typeについて、ひとつ解説をする。これを読めば、Dartの如何に大昔のJavascriptより優れているかが、一目瞭然であろう。
強い静的な型付けは、C++のような、ほとんどを静的に決定する言語では非常に便利である。しかし、動的な言語では、むしろ邪魔にさえ感じる。
Dartの型システムは、Optionalである。型を明示的に書こうが書くまいが、自由である。
変数には、型を指定してもしなくてもよい。
var x = 0 ;
int x = 0 ;
関数の引数には、型を指定してもしなくてもよい。
int f( int x ) => x ;
f( x ) => x ;
ジェネリックのタイプパラメーターには、型を指定してもしなくても良い。
List<int> l = <int>[ 1, 2, 3 ] ;
List l = [ 1, 2, 3 ] ;
異なる型を代入することもできる。
int x = "肩のうしろの2本のツノのまんなかにあるトサカの下のウロコの右" ; // static type warning
これでは、型の意味が無いではないかと思う者もいるだろう。それは、Dartにおける型の目的を理解していないからである。Dartにおける型システムは、最適化のためにあるのではないのだ。ツールを助けるためにあるのだ。
まず、Dartの変数について一言説明しておかなければならない。Dartの変数とは、「メモリー上のストレージの場所を示す」ものである。これは、Javascriptのような言語に親しい物には、馴染み深い概念である。そのような言語に馴染みのないものには、とりあえず、ポインターだと考えておけばよい。もちろん、ポインターは、実際には異なる概念である。ポインターとは、やはり、メモリー上のストレージの場所を指し示す、すなわち「アドレス」を格納するために必要なだけのサイズのストレージであって、Dartの変数ではない。DartやJavascriptのような言語では、変数はすべてメモリー上のストレージへの参照であり、その参照を格納するストレージを意識することはない。
Dartにおける変数とは、内部的には、単にオブジェクトへの参照なのだから、型という仕組みがなかったとしても、不思議ではない。たとえば、DartやJavascriptでは、
var x = 0 ;
x = 1.5 ;
x = "肩のうしろの2本のゴボウのまんなかにあるスネ毛の下のロココ調の右" ;
このようなことができる。Dartにおける「代入」とは、単に変数が参照する場所を変えているだけである。変数自体は、固定されたストレージを持たないのだ。もちろん、実装上はストレージを持つが、それはユーザー側からは隠されている。
しかし、Javascriptのように、ソースコード上では、変数が型情報を持たないとすると、少々厄介である。
たとえば、ある変数はある型だと想定して使っているのに、うっかりと別の型を代入してしまったばかりに、型が変わってしまう。もちろん、コンパイルエラーどころか、警告すら出せないので、このバグを探すのは非常に難しい。プログラマーは、自分の目でバグを探さなければならないだろう。
Dartにおける型とは、言わばannotationなのだ。
int x = 0 ;
x = 1 ; // OK
x = 1.5 ; // Static type warning.
このように、型が合わない場合、コンパイル時に警告を出すことができる。そのため、プログラマーは目でコードを探す必要がなくなる。
現代では、IDEによるコード支援が盛んである。例えば、識別子を補完したり、メソッド名を補完したりしてくれるのは、非常に便利である。ところが、Javascriptのように型がないと、これは少し難しい。
var x = "肩ぐるまして後ろ向きに乗り2本のゴボウを持った歌舞伎顔の男" ;
x. // ←ここに注目
xという識別子に続いて、ドットを使っているのに注目してもらいたい。賢いIDEならば、ドットを打った時点で、プログラマーはメソッドを呼び出したいのだと解釈し、メソッドの一覧を表示してくれることだろう。ただし、この場合、xの型を静的に求めるのは難しい。
上記のような二例であれば、静的な解析でも可能である。ところが、Javascriptには、不可能な場合もあるのだ。
function f( x )
{
x. // xは何かって? (´・ω・`)知らんがな
}
これはどうしようもない例である。
Dartでは、型をannotationのように指定することができる。そのため、静的ツールは静的に型を決定することができる。
f( String x )
{
x. // Dartならば、IDEによってメソッド名の一覧を表示可能(`・ω・´)シャキーン
}
文法上、型を書くことができるというのは、コメントで書くよりもずっと分かりやすい。
var x = 0 ; // type of x suppose to be int.
int x = 0 ; // horay! no comment is needed!
しかし、実行時に型が一致しなくても、エラーとはならない。つまり、実行を続けることができるのだ。ただし、警告は出るので、バグを見つけることができる。もし、型を固定したくなければ、varを使うこともできる。自由である!