web-dev-qa-db-ja.com

動的型言語と静的型言語

静的型言語と比較した動的型言語の利点と制限は何ですか?

参照動的言語の愛を込めて (はるかに論証的なスレッド...)

202
cvs

インタプリタの型と型変換を推測する能力は開発時間を短縮しますが、コンパイル時にキャッチする静的型付け言語では得られない実行時エラーを引き起こす可能性もあります。しかし、どちらが優れているか(またはそれが常に真実であっても)は、最近(そして長い間)コミュニティで熱く議論されています。

この問題の良い例は 可能な場合は静的な入力、必要な場合は動的な入力:プログラミング言語間の冷戦の終わり MicrosoftのErik MeijerとPeter Draytonによるものです。

静的型付けの支持者は、静的型付けの利点には、プログラミングミスの早期検出(整数へのブール値の追加の防止など)、型シグネチャの形式でのドキュメントの改善(名前の解決時に引数の数と型を組み込むなど)などが含まれると主張しますコンパイラー最適化の機会(例:レシーバーの正確な型が静的にわかっている場合の仮想呼び出しを直接呼び出しに置き換える)、ランタイム効率の向上(すべての値が動的型を保持する必要がないなど)、および設計時の開発者エクスペリエンスの向上(例:レシーバーのタイプ、IDEは、該当するすべてのメンバーのドロップダウンメニューを表示できます)。静的型付け狂信者は、「型付けされたプログラムが間違ってはいけない」と信じさせようとします。これは確かに印象的ですが、かなり空虚な声明です。静的型チェックは、プログラムの実行時の動作をコンパイル時に抽象化するものであるため、必ずしも部分的に健全で不完全なものです。これは、タイプチェッカーによって追跡されないプロパティが原因でプログラムが依然として間違っている可能性があり、間違ってはいけないもののタイプチェックできないプログラムがあることを意味します。静的型付けを部分的ではなく完全なものにする衝動により、型システムは「ファントム型」[11]や「ぐらつく型」[10]などの概念で見られるように、過度に複雑で異国的なものになります。これは、ボールとチェーンを足に縛り付けてマラソンを走ろうとするようなもので、最初の1マイルを過ぎて脱出してもほぼ成功したことを意気揚々と叫びます。

動的型付け言語の支持者は、静的型付けはあまりにも厳格であり、動的型言語の柔軟性により、要件が変化するか未知のシステムのプロトタイプ作成、または予測不可能に変化する他のシステムとの相互作用(データとアプリケーションの統合)に理想的に適していると主張します。もちろん、動的に型付けされた言語は、メソッドのインターセプト、動的なロード、モバイルコード、ランタイムリフレクションなどの真に動的なプログラムの振る舞いを処理するために不可欠です。プログラミング言語は、動的に型指定されたスクリプト言語に比べて、コードの再利用性、冗長性、安全性、表現力を低下させます。この引数は、動的に型指定されたスクリプト言語の多くの支持者によって文字通りオウムされています。これは誤fallであり、宣言型プログラミングの本質が割り当てを排除していると主張するのと同じカテゴリーに分類されると主張します。または、John Hughes [8]が言っているように、機能を省略することで言語をより強力にすることは論理的に不可能です。すべての型チェックを実行時まで遅らせることは良いことであるという事実を守ることは、開発プロセスのできるだけ早い段階でエラーをキャッチする必要があるという事実でダチョウの戦術を実行することです。

138
Vinko Vrsalovic

静的型システムは、特定のエラーを静的に排除し、プログラムを実行せずに検査し、特定の点で健全性を証明しようとします。一部の型システムは、他の型システムよりも多くのエラーをキャッチできます。たとえば、C#は適切に使用するとNULLポインター例外を排除できますが、Javaにはそのような能力はありません。 Twelfには、実際に 証明が終了することを保証する問題の停止 を「解決」する型システムがあります。

ただし、完璧な型システムはありません。特定のクラスのエラーを排除するために、ルールに違反する特定の完全に有効なプログラムも拒否する必要があります。これが、Twelfが実際に停止の問題を解決しない理由であり、奇妙な方法で終了する多数の完全に有効な証明を捨てることでそれを回避します。同様に、Javaの型システムは、異種配列を使用しているため、ClojureのPersistentVector実装を拒否します。実行時に動作しますが、型システムはそれを検証できません。

そのため、ほとんどの型システムには、静的チェッカーをオーバーライドする方法である「エスケープ」が用意されています。ほとんどの言語では、これらはキャストの形式を取りますが、一部の言語(C#やHaskellなど)には「安全でない」とマークされたモード全体があります。

主観的に、私は静的型付けが好きです。適切に実装(ヒント:notJava)、静的型システムは、運用システムがクラッシュする前にエラーを取り除くのに非常に役立ちます。動的に型付けされた言語は、より多くのユニットテストを必要とする傾向がありますが、これは最高の状態では退屈です。また、静的に型付けされた言語には、動的型システムでは不可能または安全でない特定の機能があります( 暗黙の変換 spring to mind)。それはすべて要件と主観的な好みの問題です。 Rubyで次のEclipseをビルドするのは、アセンブリでバックアップスクリプトを記述したり、Javaを使用してカーネルにパッチを適用したりすることです。

ああ、そして「xタイピングはyタイピング」は、単に煙を吹いているだけです。動的型付けは多くの場合より速く「感じる」かもしれませんが、実際にあなたの派手なアプリケーションrunを作ろうとすると、地面を失います。同様に、静的型付けは完璧なセーフティネットのように思えるかもしれませんが、Javaのより複雑なジェネリック型定義のいくつかを見ると、ほとんどの開発者が目が見えない人を恐れています。型システムと生産性があっても、特効薬はありません。

最後の注意:静的タイピングと動的タイピングを比較するとき、パフォーマンスを心配しないでください。 V8やTraceMonkeyなどの最新のJITは、静的言語のパフォーマンスに危険なほど近づいています。また、Javaが実際に本質的に動的な中間言語にコンパイルされるという事実は、ほとんどの場合、動的タイピングは一部の人々がそうするような大きなパフォーマンスのキラーではないことを示唆するはずです。

119
Daniel Spiewak

まあ、どちらも非常に、非常に非常に非常に誤解されており、2つのまったく異なるものでもあります。 相互に排他的ではない

静的型は、言語の文法の制限です。静的に型付けされた言語は厳密に文脈自由ではないと言うことができます。簡単な真実は、すべてのデータを単純にビットベクトルとして扱わない文脈自由文法で言語を健全に表現するのは不便になるということです。静的型システムは、もしあれば言語の文法の一部であり、文脈自由文法ができる以上に単純に制限しているため、文法チェックはソースの2つのパスで実際に行われます。静的型は型理論の数学的概念に対応し、数学の型理論はいくつかの表現の合法性を制限するだけです。たとえば、数学では3 + [4,7]とは言えませんが、これは型理論のためです。

したがって、静的型は、理論的な観点から「エラーを防ぐ」方法ではなく、文法の制限です。確かに、+、3、および間隔に通常の集合理論定義がある場合、型システム3 + [4,7]を削除すると、集合であるかなり明確に定義された結果が得られます。 「ランタイム型エラー」は理論的には存在しません。型システムの実際の使用法は、人間に対して意味をなさない操作を防ぐことです。もちろん、操作は単なるビットのシフトと操作にすぎません。

これの難点は、型システムが、そのような操作が実行されるかどうかを決定できず、実行が許可されるかどうかです。同様に、「タイプエラー」が発生する可能性のあるプログラムとそうでないプログラムのすべての可能なプログラムのセットを正確にパーティション分割します。次の2つのことしかできません。

1:プログラムで型エラーが発生することを証明する
2:プログラムで発生しないことを証明する

これは自分が矛盾しているように見えるかもしれません。しかし、CまたはJava型チェッカーは、プログラムを 'ungrammatical'として拒否するか、または 't2で成功します。発生しないことを証明することはできません。それは、発生しないことを意味するものではなく、単に証明できないことを意味します。型エラーのないプログラムは、コンパイラによって証明できないという理由だけで拒否される可能性が非常に高いかもしれません。単純な例はif(1) a = 3; else a = "string";です。これは常にtrueであるため、else-branchはプログラム内で実行されることはなく、型エラーは発生しません。しかし、これらのケースを一般的な方法で証明することはできないため、拒否されました。これは静的に型付けされた多くの言語の大きな弱点です。自分自身からあなたを守ることは、必要のない場合にも必然的に守られます。

しかし、一般に信じられていることに反して、原則1で機能する静的型付け言語もあります。型エラーを引き起こす可能性があることを証明できるすべてのプログラムを単に拒否し、できないすべてのプログラムを渡します。そのため、型エラーのあるプログラムを許可する可能性があります。良い例は型付きラケットで、動的型と静的型のハイブリッドです。そして、このシステムで両方の長所を利用できると主張する人もいます。

静的型付けのもう1つの利点は、コンパイル時に型が認識されるため、コンパイラがこれを使用できることです。 Javaで"string" + "string"または3 + 3を実行すると、最後のテキストの+トークンは両方とも完全に異なる操作とデータムを表し、コンパイラーはどちらを選択するかを認識しますタイプだけ。

さて、ここで非常に物議を醸す声明を発表しますが、私は我慢します:「動的型付け」は存在しません

非常に物議をかもしますが、それは本当です、動的に型付けされた言語は理論的な観点からですuntyped。それらは静的に型付けされた言語で、型は1つだけです。または、簡単に言えば、実際には文脈自由文法によって実際に文法的に生成される言語です。

なぜ型を持たないのですか?すべての操作はすべてのオペラントで定義および許可されているため、「ランタイム型エラー」とは正確には何ですか?これは、純粋に副作用の理論的な例です。文字列を出力するprint("string")が操作である場合、length(3)もそうです。前者はstringを標準出力に書き込み、後者は単にerror: function 'length' expects array as argument. 、 それでおしまい。理論的には、動的に型付けされた言語のようなものはありません。それらはuntyped

さて、「動的に型付けされた」言語の明らかな利点は表現力であり、型システムは表現力の制限に他なりません。そして、一般に、型システムを持つ言語は、型システムが単に無視された場合に許可されないすべての操作に対して実際に定義された結果を持ち、結果は人間にとって意味がありません。多くの言語は、型システムを適用した後、チューリングの完全性を失います。

明らかな欠点は、人間には無意味な結果をもたらす操作が発生する可能性があるという事実です。これを防ぐために、通常、動的型付け言語はこれらの操作を再定義します。無意味な結果を生成するのではなく、エラーを書き出し、プログラムを完全に停止するという副作用をもたらすように再定義します。これはまったく「エラー」ではありません。実際、言語仕様は通常これを意味します。これは、理論的な観点から文字列を出力するのと同じくらいの言語の動作です。したがって、型システムは、プログラマーにコードの流れについて推論させ、これが起こらないようにします。または、確かに、doesが発生する理由は、デバッグのいくつかの点で便利な場合があり、「エラー」ではなく、言語の明確に定義されたプロパティであることを示します。実際、ほとんどの言語にある「動的型付け」の残りの部分は、ゼロによる除算を防ぐことです。これは動的型付けです。型はありません。ゼロ以外の型はありません。ゼロは他のすべての数値とは異なる型です。 「タイプ」と呼ばれるものは、配列の長さや文字列の最初の文字など、データムの別のプロパティにすぎません。また、多くの動的型付け言語では、"error: the first character of this string should be a 'z'"などの記述も可能です。

別のことは、動的に型指定された言語は実行時に使用可能な型を持ち、通常はそれをチェックして処理し、それから決定できることです。もちろん、理論的には、配列の最初の文字にアクセスし、それが何であるかを見ることに違いはありません。実際、独自の動的Cを作成し、long long intのような1つの型のみを使用し、その最初の8ビットを使用して「型」を保存し、それに応じてチェックしてfloatまたは整数の加算を実行する関数を記述します。 1つのタイプを持つ静的に型付けされた言語、または動的言語があります。

実際には、これらすべてが示すように、静的型付け言語は一般に商用ソフトウェアの作成のコンテキストで使用されますが、動的型付け言語はいくつかの問題を解決し、いくつかのタスクを自動化するコンテキストで使用される傾向があります。静的に型付けされた言語でコードを書くことは単純に時間がかかり、大丈夫だとわかっていることはできませんが、型システムはあなたが犯さないエラーに対してあなた自身を保護するため、面倒です。多くのコーダーは、システム内にあるためにこれを行うことすら認識していませんが、静的言語でコーディングする場合、型システムではうまくいかないことができないという事実を回避することがよくあります。それがうまくいかないことを証明することはできません。

私が述べたように、一般に「静的に型付けされた」とは、無罪であると証明されるまで有罪であるケース2を意味します。しかし、型理論から型システムをまったく導出しない言語の中には、ルール1を使用しているものもあります。だから、多分型付きラケットはあなたのためです。

また、より不合理で極端な例として、現在、「タイプ」が配列の最初の文字であり、データ、「タイプ」、「タイプ」のデータである言語を実装しています型とデータム、それ自体を型として持つ唯一のデータム。型は有限ではなく、静的に制限されていませんが、実行時情報に基づいて新しい型が生成される場合があります。

45
Zorf

おそらく、動的タイピングの最大の「利点」は、学習曲線が浅くなることです。学習する型システムはなく、型制約などのコーナーケースの非自明な構文もありません。これにより、より多くの人々が動的型付けにアクセスできるようになり、洗練された静的型システムが手の届かない多くの人々にとって実行可能になります。その結果、動的タイピングは、教育(MITのScheme/Pythonなど)および非プログラマ向けのドメイン固有言語(e.g. Mathematica )で普及しています。動的言語は、競合がほとんどまたはまったくないニッチ(たとえば、Javascript)にも浸透しています。

最も簡潔で動的に型付けされた言語(Perl、APL、J、K、 Mathematica )はドメイン固有であり、最も簡潔で汎用的な静的型付け言語(たとえば- OCaml )設計されたニッチで。

動的型付けの主な欠点は次のとおりです。

  • 実行時タイプのエラー。

  • 同じレベルの正確さを達成するのは非常に困難であるか、実際上不可能である可能性があり、さらに多くのテストが必要です。

  • コンパイラ検証済みのドキュメントはありません。

  • パフォーマンスの低下(通常は実行時ですが、代わりにコンパイル時の場合があります(例:スターリンスキーム))。高度な最適化への依存による予測不可能なパフォーマンス。

個人的には、私は動的言語で育ちましたが、他に実行可能な選択肢がない限り、専門家として40の極に触れることはありませんでした。

25
Jon Harrop

Artimaの入力:強対弱、静的対動的の記事から:

厳密な型指定により、不一致の型の間での操作の混合が防止されます。タイプを混在させるには、明示的な変換を使用する必要があります

弱い型付けは、明示的な変換なしで型を混在させることができることを意味します

Pascal Costanzaの論文動的vs静的型付け—パターンベースの分析(PDF)で、彼は場合によっては、静的型付けは動的型付けよりもエラーが発生しやすいことがあります。一部の静的型付け言語では、「正しいこと」を行うために動的型付けを手動でエミュレートする必要があります。 Lambda the Ultimate で説明されています。

12
Mark Cidade

コンテキストに依存します。動的型付けシステムおよび強い型付けに適した多くの利点があります。私は、動的型言語の流れがより高速であると考えています。動的言語は、クラス属性や、コードで何が起こっているのかを考えるコンパイラーに制約されません。ちょっとした自由があります。さらに、通常、動的言語は表現力が豊かで、結果としてコードが少なくなります。これにもかかわらず、エラーが発生しやすく、これも疑わしく、単体テストのカバーに依存します。動的な言語を使用した簡単なプロトタイプですが、メンテナンスは悪夢になります。

静的型付きシステムの主な利点は、IDEのサポートとコードの確実な静的アナライザーです。コードを変更するたびに、コードに自信を持つようになります。メンテナンスは、このようなツールで簡単に行えます。

3
AndrewG

仕事に最適なツールがすべてです。どちらも常に100%優れているわけではありません。どちらのシステムも人間が作成したもので、欠陥があります。申し訳ありませんが、完璧なものを作ります。

動的型付けは私の邪魔にならないので好きですが、はい、実行時エラーは私が計画していなかったように忍び寄ることができます。静的型付けは前述のエラーを修正するかもしれませんが、初心者(型付け言語)プログラマーを定数charと文字列の間でキャストしようと夢中にさせます。

0
J.J.

静的言語と動的言語にはさまざまなものがあります。私にとっての主な違いは、動的言語では変数の型が固定されていないことです。代わりに、タイプは値に関連付けられています。このため、実行される正確なコードは実行時まで不定です。

初期またはナイーブの実装では、これは大きなパフォーマンスの低下になりますが、最新のJITは、静的コンパイラーの最適化で得られる最高の結果に非常に近づきます。 (一部のフリンジケースでは、それよりも優れています)。

0
Javier