型がないということは、本当に素晴らしいことです。型がないことによって、たくさんの面倒から解放されるからです。冒頭のこれが、「静的型付き言語にはメリットが(ほとんど)ない」と言っているように思えてしまいます。コメントのやり取りを見ても、ある程度そう考えているように受け取れます。勘違いなどが多く見られたので、補足というか、反論というか、そんな感じのことを書きます。追記:ごく一部、このエントリを「動的型付き言語と静的型付き言語を比べて、静的型付き言語の方が素晴らしい言語である」ということを言うためのものだと勘違いしている人を見かけました。このエントリは、そこについては言及していません。元記事で「動的型付き言語のメリット」とされている部分について、「そうではないよ」と指摘するためのエントリです。どのような型の値でも代入できる?これは、「変数に型を明示する必要がない」ということですよね。型推論によって、静的型付き言語であっても変数の型は明示不要です。Perlの方の$personをクラス的な何かと勘違いしてたので、連想配列に合わせました。LWP.UserAgent()と、ほとんど変わらない記述が可能です。記述量がとても短くなる?これは、上の例で説明したように、型推論機能さえあればほとんど問題になりません。型推論が不完全のくだりは取り下げているので触れません。一部を手軽に確認することが可能です。ScalaやF#など、対話環境を持った静的型付き言語はいろいろと存在します。その実装が難しくなるかどうかは判断がつかないです。変数に型がないと変更に強い?ここで言っているのは、おそらくこういうことでしょう。c.client();という変更が必要になる、と。あれば、ここでも型推論により解決されます。c.client()それはともかくとして、このように局所的な例だけで変更に強い、としてしまうのには違和感が残ります。「変更に強い場合がある」程度ならいいのですが、それだとメリットになりませんよね。変数に型がないことによって、関数の重複を減らすことができるという大きなメリットがあります。これはどういうことかよくわかりません。sumが重複している?これを「大きなメリット」と呼ぶのはつらい気がします。それと、オーバーロードを持たない静的型付き言語のことも、たまには思い出してあげてください。ちなみに、F#ではメソッドでのみオーバーロードが可能で、関数でのオーバーロードはできません。するか?判別共用体というものを使います。型を定義したことによって大きなメリットが生まれます。それは、考慮漏れや、一致しない条件をコンパイル時に発見してもらえるようになることです。「Aの処理は汎用的でいいんだけど、(高速化のために)2要素以下の時は直接計算したい」という要望が上がったとします。0こう書いてしまった場合、後ろ3行のケースにはどうやってもたどり着けません。...のケースがそれらのケースでも当てはまってしまうからです。これを、F#コンパイラは警告として知らせてくれます。*)今度は、修正を間違ってBのケースを消してしまいました。この場合でも、F#コンパイラは「Bのケースが考慮されていない」という警告で知らせてくれます。これに対しても「発見が早いか遅いかの違いだ」と言うことはできるでしょう。バグの発見は早ければ早いほどその修正は楽であることが多いのです。その条件分岐に対するテストを書き忘れるというミスも起こりえます。いう言語を使うことである種のバグはなくなるのです。その中にはほかの言語では「値レベルの問題」である、NullPointerExceptionの問題も含まれます。OptionやMaybeについて調べてみるといいでしょう。変数に型がないことによって、クラスの実装が重複がなくとてもシンプルになります。変数に型があるなしと、クラスの実装の重複にどのような関係があるのでしょうか?C++のテンプレートのような機能も必要がない?ここは、「何でもかんでも1つの関数に詰め込むことができる」と言っているように思えます。これをメリットに含めるのは無理があります。型があれば「その関数にどんなものが渡せ、どんなものが返ってくるのか」程度の情報は得られます。intであれば、「リスト(入っている要素は何でもいい)を受け取って、intを返す」ことがわかります。他にも、「(よほどマジカルなことをしていない限りは)この関数はリストの各要素には用はないのだな」ということもわかりますし、「引数は一つしかとらない」という確信を得ることもできます。ここではfなんていう適当な名前を付けましたが、これも適切な名前にすればさらにドキュメント性は高まります。この種の判断を、動的型付き言語ではドキュメントに頼るか、自分で関数を読み解く必要があります。間違いも犯しやすくなっていきます。静的言語はインターフェースやクラスをそのたびに実装しなければならないので、修正や変更が行いづらいです。その点では、保守性は低いといえます。いうのは色々と勘違いが含まれています。インターフェイスやクラスを実装することは必須ではない静的型付き言語であってもインターフェイスやクラスをそのたびに実装しなければいけないわけではありません。x.nameのように、「nameを持つ型」という指定が可能です。nameさえ持っていれば、どんなものでもこのメソッドに渡せます。xのように、同じく「nameを持つ型」という指定が可能です。静的型付き言語の方が修正が容易なものも多い静的型付きの言語は、外部に影響を与えるような修正は動的型付き言語に比べて容易です。変更してエラーになった部分を潰していけば修正作業は終了です。コンパイルのチェックはテストにも及ぶため、テスト側の修正漏れの恐れもありません。IDEによっては、そもそもこの種の変更をIDEが自動でやってくれるものもあります。それに対して、動的型付き言語の場合、どこかのテストに不備があった場合、バグを埋め込んでしまうことになります。思うに、動的型付き言語の「修正の行いやすさ」は、メソッド内や、クラス内に閉じている場合のみに言えるのではないでしょうか。その「変更の強さ」は「バグの埋め込みやすさ」に直結している例えばあるインターフェイスにメソッドを追加した場合、その実装クラスすべてにメソッドを実装する必要があります*2。これを指して「静的型付き言語は変更に弱く、動的型付き言語は変更に強い」としているのであれば、「変更の強さ」についての考えが甘いでしょう。確かに、動的型付き言語であれば実装クラスにメソッドを追加するだけで「そのまま動かす」ことは可能です。それは「正しく」動き続けているわけではありません。実装クラスにメソッドを追加したということは、それがどこかで使われる、ということです。どこかでその追加したメソッドを呼び出すようにして、そのメソッドを呼び出すためのレシーバとして使っているインスタンスがほとんどの場合メソッドを追加した実装クラスだったとしても、たった1パターンでも違うクラスのインスタンスが入ってくるような場合、それをどうやって修正するのでしょうか。静的型付き言語では、確かにインターフェイスにメソッドを追加しただけでは「そのまま動かす」ことは無理ですが、コンパイルエラーを潰せば「正しく」することは容易ですし、IDEの力によって「このメソッドを呼び出している個所を洗い出す」ことも容易です。全体を通してコメント欄含め、全体を通してみると、テストを過信しすぎです。全数テストでもやらない限り、テストで「保証」を得ることはできません。静的な型があればバグが減るのかどうかですが、最終的なバグの数(システムに残ってしまう見つからなかったor放置されたバグの数)は同じくらいになるかもしれません。バグの絶対数(システムが死に絶えるまでに見つかったバグの数)は減るはずです。動的型付き言語であれば埋め込んだであろうバグを、そもそも入れ込まなくなるから。品質どうこうは置いておいたとしても、この点は非常に重要です。例に挙げられていたsum関数のテストですが、sum関数自体のテストはそれほど手間は変わらないでしょう。直接的でないにしても行う必要があります。この確認に一つでも漏れがあった場合、それは静的型付き言語では埋め込みえなかったバグです。静的型付き言語では、sum関数呼び出し時の型に関するテストは不要ですし、漏れもないことが保証されます。いった言語を実際に使ってそれなりの大きさのシステムを構築してみれば、テストの絶対数が少なくなることを感じれるはずですよ。レコードで値オブジェクトを簡単に作る業務で使う関数型言語の第一回は、レコードについてです。(1)検索はてなブログをはじめよう!bleis-tiftさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。