静的型言語と比較した動的型言語の利点と制限は何ですか?
参照:動的言語への愛を込めて(はるかに議論の余地のあるスレッド...)
静的型言語と比較した動的型言語の利点と制限は何ですか?
参照:動的言語への愛を込めて(はるかに議論の余地のあるスレッド...)
型と型変換を推定するインタープリターの機能により、開発時間が短縮されますが、コンパイル時にキャッチする静的に型付けされた言語では取得できない実行時エラーを引き起こす可能性もあります。しかし、どちらが優れているか (またはそれが常に正しい場合でも) は、最近 (そして長い間) コミュニティで熱く議論されています。
この問題については、Microsoft の Erik Meijer と Peter Drayton によるStatic Typing Where possible, Dynamic Typing When Needed: The End of the Cold War Between Programming Languagesからの引用をお勧めします。
静的型付けの支持者は、静的型付けの利点には、プログラミングの誤りの早期発見 (ブール値に整数を追加するのを防ぐなど)、型シグネチャの形でのより適切な文書化 (名前解決時に引数の数と型を組み込むなど) などがあると主張しています。コンパイラの最適化 (例: レシーバーの正確な型が静的にわかっている場合に仮想呼び出しを直接呼び出しに置き換える)、実行時の効率の向上 (例: すべての値が動的な型を保持する必要はない)、および設計時の開発者エクスペリエンスの向上 (例:受信者のタイプ、IDE は該当するすべてのメンバーのドロップダウン メニューを表示できます)。静的型付けの狂信者は、「適切に型付けされたプログラムは失敗しない」と私たちに信じ込ませようとします。これは確かに印象的ですが、それはかなり空虚な声明です。静的型チェックは、プログラムの実行時の動作をコンパイル時に抽象化したものであるため、必ずしも部分的にしか正しくなく、不完全です。これは、タイプチェッカーによって追跡されないプロパティが原因で、プログラムがまだ間違っている可能性があること、および、間違っていることはないがタイプチェックできないプログラムがあることを意味します。静的型付けを部分的ではなく完全なものにしたいという衝動は、「ファントム型」[11] や「不安定な型」[10] などの概念が示すように、型システムを過度に複雑で風変わりなものにします。これは、足にボールとチェーンを結び付けてマラソンを走ろうとして、最初の 1 マイルで脱出したにもかかわらず、あと少しで完走できると誇らしげに叫ぶようなものです。静的型チェックは、プログラムの実行時の動作をコンパイル時に抽象化したものであるため、必ずしも部分的にしか正しくなく、不完全です。これは、タイプチェッカーによって追跡されないプロパティが原因で、プログラムがまだ間違っている可能性があること、および、間違っていることはないがタイプチェックできないプログラムがあることを意味します。静的型付けを部分的ではなく完全なものにしたいという衝動は、「ファントム型」[11] や「不安定な型」[10] などの概念が示すように、型システムを過度に複雑で風変わりなものにします。これは、足にボールとチェーンを結び付けてマラソンを走ろうとして、最初の 1 マイルで脱出したにもかかわらず、あと少しで完走できると誇らしげに叫ぶようなものです。静的型チェックは、プログラムの実行時の動作をコンパイル時に抽象化したものであるため、必ずしも部分的にしか正しくなく、不完全です。これは、タイプチェッカーによって追跡されないプロパティが原因で、プログラムがまだ間違っている可能性があること、および、間違っていることはないがタイプチェックできないプログラムがあることを意味します。静的型付けを部分的ではなく完全なものにしたいという衝動は、「ファントム型」[11] や「不安定な型」[10] などの概念が示すように、型システムを過度に複雑で風変わりなものにします。これは、足にボールとチェーンを結び付けてマラソンを走ろうとして、最初の 1 マイルで脱出したにもかかわらず、あと少しで完走できると誇らしげに叫ぶようなものです。したがって、それは必然的に部分的にのみ健全で不完全です。これは、タイプチェッカーによって追跡されないプロパティが原因で、プログラムがまだ間違っている可能性があること、および、間違っていることはないがタイプチェックできないプログラムがあることを意味します。静的型付けを部分的ではなく完全なものにしたいという衝動は、「ファントム型」[11] や「不安定な型」[10] などの概念が示すように、型システムを過度に複雑で風変わりなものにします。これは、足にボールとチェーンを結び付けてマラソンを走ろうとして、最初の 1 マイルで脱出したにもかかわらず、あと少しで完走できると誇らしげに叫ぶようなものです。したがって、それは必然的に部分的にのみ健全で不完全です。これは、タイプチェッカーによって追跡されないプロパティが原因で、プログラムがまだ間違っている可能性があること、および、間違っていることはないがタイプチェックできないプログラムがあることを意味します。静的型付けを部分的ではなく完全なものにしたいという衝動は、「ファントム型」[11] や「不安定な型」[10] などの概念が示すように、型システムを過度に複雑で風変わりなものにします。これは、足にボールとチェーンを結び付けてマラソンを走ろうとして、最初の 1 マイルで脱出したにもかかわらず、あと少しで完走できると誇らしげに叫ぶようなものです。また、エラーが発生することはありませんが、タイプチェックできないプログラムがあること。静的型付けを部分的ではなく完全なものにしたいという衝動は、「ファントム型」[11] や「不安定な型」[10] などの概念が示すように、型システムを過度に複雑で風変わりなものにします。これは、足にボールとチェーンを結び付けてマラソンを走ろうとして、最初の 1 マイルで脱出したにもかかわらず、あと少しで完走できると誇らしげに叫ぶようなものです。また、エラーが発生することはありませんが、タイプチェックできないプログラムがあること。静的型付けを部分的ではなく完全なものにしたいという衝動は、「ファントム型」[11] や「不安定な型」[10] などの概念が示すように、型システムを過度に複雑で風変わりなものにします。これは、足にボールとチェーンを結び付けてマラソンを走ろうとして、最初の 1 マイルで脱出したにもかかわらず、あと少しで完走できると誇らしげに叫ぶようなものです。
動的型付け言語の支持者は、静的型付けは硬直的すぎると主張し、動的言語の柔らかさは、変化する要件や未知の要件を持つシステムのプロトタイピング、または予測不可能に変化する他のシステム (データとアプリケーションの統合) と相互作用するシステムに理想的に適していると主張しています。もちろん、動的型付け言語は、メソッド インターセプト、動的ローディング、モバイル コード、ランタイム リフレクションなどの真に動的なプログラムの動作を扱うために不可欠です。プログラミング言語は、動的に型付けされたスクリプト言語よりもコードを再利用しにくく、冗長にし、安全性を低下させ、表現力を低下させます。この議論は、動的に型付けされたスクリプト言語の多くの支持者によって文字通りオウム返しされています。これは誤謬であり、宣言型プログラミングの本質は割り当てを排除することであると主張するのと同じカテゴリに分類されると主張します。または、John Hughes が言うように [8]、機能を省略して言語をより強力にすることは論理的に不可能です。すべての型チェックを実行時まで遅らせることは良いことであるという事実を擁護することは、開発プロセスのできるだけ早い段階でエラーを検出する必要があるという事実を利用してダチョウの戦術を実行することです。機能を省略して言語をより強力にすることは、論理的に不可能です。すべての型チェックを実行時まで遅らせることは良いことであるという事実を擁護することは、開発プロセスのできるだけ早い段階でエラーを検出する必要があるという事実を利用してダチョウの戦術を実行することです。機能を省略して言語をより強力にすることは、論理的に不可能です。すべての型チェックを実行時まで遅らせることは良いことであるという事実を擁護することは、開発プロセスのできるだけ早い段階でエラーを検出する必要があるという事実を利用してダチョウの戦術を実行することです。
Static type systems seek to eliminate certain errors statically, inspecting the program without running it and attempting to prove soundness in certain respects. Some type systems are able to catch more errors than others. For example, C# can eliminate null pointer exceptions when used properly, whereas Java has no such power. Twelf has a type system which actually guarantees that proofs will terminate, "solving" the halting problem.
However, no type system is perfect. In order to eliminate a particular class of errors, they must also reject certain perfectly valid programs which violate the rules. This is why Twelf doesn't really solve the halting problem, it just avoids it by throwing out a large number of perfectly valid proofs which happen to terminate in odd ways. Likewise, Java's type system rejects Clojure's PersistentVector
implementation due to its use of heterogeneous arrays. It works at runtime, but the type system cannot verify it.
For that reason, most type systems provide "escapes", ways to override the static checker. For most languages, these take the form of casting, though some (like C# and Haskell) have entire modes which are marked as "unsafe".
Subjectively, I like static typing. Implemented properly (hint: not Java), a static type system can be a huge help in weeding out errors before they crash the production system. Dynamically typed languages tend to require more unit testing, which is tedious at the best of times. Also, statically typed languages can have certain features which are either impossible or unsafe in dynamic type systems (implicit conversions spring to mind). It's all a question of requirements and subjective taste. I would no more build the next Eclipse in Ruby than I would attempt to write a backup script in Assembly or patch a kernel using Java.
Oh, and people who say that "x typing is 10 times more productive than y typing" are simply blowing smoke. Dynamic typing may "feel" faster in many cases, but it loses ground once you actually try to make your fancy application run. Likewise, static typing may seem like it's the perfect safety net, but one look at some of the more complicated generic type definitions in Java sends most developers scurrying for eye blinders. Even with type systems and productivity, there is no silver bullet.
Final note: don't worry about performance when comparing static with dynamic typing. Modern JITs like V8 and TraceMonkey are coming dangerously-close to static language performance. Also, the fact that Java actually compiles down to an inherently dynamic intermediate language should be a hint that for most cases, dynamic typing isn't the huge performance-killer that some people make it out to be.
ええと、どちらも非常に非常に非常に誤解されており、2 つのまったく異なるものでもあります。相互に排他的ではありません。
静的型は、言語の文法の制限です。静的に型付けされた言語は、厳密には文脈自由ではないと言えます。単純な真実は、すべてのデータを単純にビットベクトルとして扱わない文脈自由文法で言語を正気で表現するのは不便になるということです。静的型システムは、もしあれば言語の文法の一部であり、文脈自由文法よりも制限するだけであり、文法チェックは実際にはソース上で 2 つのパスで行われます。静的型は、型理論の数学的概念に対応します。数学における型理論は、いくつかの式の正当性を単純に制限します。同様に、数学では言えません3 + [4,7]
が、これは型理論によるものです。
したがって、静的型は、理論的な観点から「エラーを防ぐ」方法ではなく、文法の制限です。実際、+、3、および間隔が通常のセットの理論的定義を持っている場合、型システムを削除すると3 + [4,7]
、セットであるかなり明確に定義された結果が得られます。「ランタイム型エラー」は理論的には存在しません。型システムの実際の用途は、人間にとって意味のない操作を防ぐことです。もちろん、操作はビットのシフトと操作にすぎません。
これの問題点は、型システムがそのような操作が発生するかどうか、実行が許可されるかどうかを判断できないことです。のように、すべての可能なプログラムのセットを、「タイプ エラー」が発生するプログラムとそうでないプログラムに正確に分割します。次の 2 つのことしかできません。
1: プログラムで型エラーが発生する
ことを証明する 2: プログラムで型エラーが発生しないことを証明する
これは、私が自分自身と矛盾しているように見えるかもしれません。しかし、C または Java の型チェッカーが行うことは、プログラムを「非文法的」として拒否するか、または 2 で成功できない場合は「型エラー」と呼びます。それらが発生しないことを証明することはできません。それは、それらが発生しないという意味ではなく、それを証明できないことを意味します. コンパイラによって証明できないという理由だけで、型エラーを持たないプログラムが拒否される可能性が非常に高いです。簡単な例はif(1) a = 3; else a = "string";
、確かに常に true であるため、else-branch はプログラム内で実行されることはなく、型エラーは発生しません。しかし、これらのケースを一般的な方法で証明することはできないため、却下されます。これは、多くの静的型付け言語の主な弱点です。自分自身を保護する上で、必要のない場合でも必然的に保護されます。
しかし、一般に信じられていることとは反対に、原則 1 で動作する静的に型付けされた言語もあります。それらは、型エラーを引き起こすことが証明できるすべてのプログラムを単純に拒否し、それができないすべてのプログラムを渡します。そのため、型エラーのあるプログラムを許可する可能性があります。良い例は Typed Racket で、動的型付けと静的型付けのハイブリッドです。そして、このシステムで両方の世界を最大限に活用できると主張する人もいます.
静的型付けのもう 1 つの利点は、型がコンパイル時に認識されるため、コンパイラがこれを使用できることです。Java で"string" + "string"
orを実行した場合、最終的にテキスト内の3 + 3
両方の+
トークンがまったく異なる操作とデータを表している場合、コンパイラは型だけからどちらを選択するかを認識します。
ここで、非常に物議を醸す発言をしようと思いますが、我慢してください。「動的型付け」は存在しません。
非常に物議を醸すように聞こえますが、動的に型付けされた言語は、理論的な観点からuntypedであることは事実です。これらは、型が 1 つしかない静的型付け言語です。または簡単に言えば、実際に文脈自由文法によって文法的に生成された言語です。
なぜタイプがないのですか?すべての操作が定義され、すべてのオペラントで許可されているため、「実行時型エラー」とは正確には何ですか? これは、純粋に副作用である理論的な例からのものです。print("string")
文字列を出力することが操作である場合、前者は標準出力にlength(3)
書き込むという副作用があり、後者は単に、それだけです。理論的な観点からは、動的型付け言語のようなものはありません。それらは型付けされていませんstring
error: function 'length' expects array as argument.
「動的に型付けされた」言語の明らかな利点は表現力です。型システムは表現力の制限に他なりません。そして一般に、型システムを持つ言語は、型システムが単に無視された場合、許可されないすべての操作に対して実際に定義された結果を持ち、その結果は人間にとって意味をなさないでしょう. 多くの言語は、型システムを適用した後、チューリングの完全性を失います。
明らかな欠点は、人間にとって無意味な結果を生成する操作が発生する可能性があるという事実です。これを防ぐために、動的に型付けされた言語は通常、これらの操作を再定義します。無意味な結果を生成するのではなく、エラーを書き出してプログラムを完全に停止させるという副作用を持つように再定義します。これはまったく「エラー」ではありません。実際、言語仕様は通常これを暗示しています。これは、理論的な観点から文字列を出力するのと同じくらい言語の動作です。したがって、型システムは、プログラマーがコードの流れについて推論して、これが起こらないようにすることを強制します。または実際、そうするように理由付けますまた、これが「エラー」ではなく、言語の明確に定義されたプロパティであることを示して、デバッグのいくつかの点で便利な場合もあります。実際、ほとんどの言語が持つ「動的型付け」の残りの 1 つは、ゼロによる除算を防ぐことです。これが動的型付けです。型はありません。ゼロが他のすべての数値とは異なる型であること以外に、型はありません。人々が「タイプ」と呼ぶものは、配列の長さや文字列の最初の文字など、データの別のプロパティです。また、多くの動的型付け言語では、 のようなものを書き出すこともできます"error: the first character of this string should be a 'z'"
。
もう1つのことは、動的に型付けされた言語は実行時に利用可能な型を持ち、通常はそれをチェックして処理し、それから決定できるということです。もちろん、理論的には、配列の最初の char にアクセスしてそれが何であるかを確認するのと同じです。実際、独自の動的 C を作成できます。long long int のような 1 つの型のみを使用し、その最初の 8 ビットを使用して「型」を格納し、それに応じてそれをチェックして float または整数の加算を実行する関数を記述します。1 つの型を持つ静的に型付けされた言語、または動的言語があります。
実際には、これらすべてが示しているように、静的に型付けされた言語は一般に商用ソフトウェアを作成するコンテキストで使用されますが、動的に型付けされた言語は、いくつかの問題を解決し、いくつかのタスクを自動化するコンテキストで使用される傾向があります。静的に型付けされた言語でコードを書くのは、単純に時間がかかり面倒です。なぜなら、うまくいくことがわかっていることを実行することはできないからです。しかし、型システムは、あなたが犯していないエラーからあなたを守ってくれます。多くのコーダーは、自分たちのシステムにあるため、これを行っていることにさえ気づいていません。間違いがないことを証明することはできません。
私が指摘したように、「静的に型付けされた」とは、一般にケース 2 を意味し、無実であることが証明されるまで有罪です。しかし、型理論から型システムをまったく派生させない一部の言語は、規則 1 を使用します。だから、多分タイプドラケットはあなたのためです.
また、もっとばかげた極端な例として、私は現在、「型」が本当に配列の最初の文字である言語を実装しています。それらはデータ、「型」のデータ、「型」自体です。タイプとデータム、それ自体がタイプとして存在する唯一のデータム。型は有限ではなく、静的に制限されていませんが、ランタイム情報に基づいて新しい型が生成される場合があります。
おそらく、動的型付けの最大の「利点」は、学習曲線が浅いことです。学ぶべき型システムはなく、型制約などの特殊なケースのための重要な構文もありません。これにより、より多くの人が動的型付けにアクセスできるようになり、洗練された静的型付けシステムに手が届かない多くの人が実行可能になります。その結果、動的型付けは、教育 (MIT の Scheme/Python など) や非プログラマー向けのドメイン固有言語 ( Mathematicaなど) のコンテキストで人気を博しています。動的言語は、競合がほとんどまたはまったくないニッチ市場でも人気を博しています (Javascript など)。
最も簡潔な動的型付け言語 (Perl、APL、J、K、Mathematicaなど) はドメイン固有であり、最も簡潔な汎用静的型付け言語 ( OCamlなど) よりも、ニッチ向けに設計された分野で大幅に簡潔になる可能性があります。 .
動的型付けの主な欠点は次のとおりです。
ランタイム タイプ エラー。
同じレベルの正確さを達成することは非常に困難であるか、事実上不可能である可能性があり、さらに多くのテストが必要になります。
コンパイラ検証済みのドキュメントはありません。
パフォーマンスの低下 (通常は実行時ですが、スターリン スキームなどのコンパイル時など) と、洗練された最適化への依存による予測不能なパフォーマンス。
個人的に、私は動的言語で育ちましたが、他に実行可能な選択肢がない限り、プロとして 40 フィートのポールで動的言語に触れることはありませんでした。
Artima のTyping: Strong vs. Weak, Static vs. Dynamicの記事から:
厳密な型指定により、一致しない型間での操作の混在が防止されます。タイプを混在させるには、明示的な変換を使用する必要があります
弱い型付けとは、明示的な変換なしで型を混在させることができることを意味します
Pascal Costanza の論文、Dynamic vs. Static Typing — A Pattern-Based Analysis (PDF) では、静的型付けは動的型付けよりもエラーが発生しやすい場合があると主張しています。一部の静的型付け言語では、「正しいこと」を行うために動的型付けを手動でエミュレートする必要があります。Lambda the Ultimateで議論されています。
それは文脈に依存します。動的型付けシステムと強い型付けシステムに適した多くの利点があります。私は、動的型言語の流れの方が速いと考えています。動的言語は、コード内で何が起こっているかを考えるクラス属性やコンパイラーに制約されません。あなたにはある種の自由があります。さらに、動的言語は通常、より表現力があり、結果としてコードが少なくて済みます。それにもかかわらず、エラーが発生しやすく、これも疑わしく、単体テストのカバーに大きく依存しています。動的言語を使用した簡単なプロトタイプですが、メンテナンスは悪夢になる可能性があります。
静的型付けシステムに対する主なメリットは、IDE サポートとコードの静的アナライザーです。コードを変更するたびに、コードに自信が持てるようになります。このようなツールがあれば、メンテナンスは簡単です。
静的言語と動的言語にはさまざまな点があります。私にとっての主な違いは、動的言語では変数の型が固定されていないことです。代わりに、型は値に関連付けられています。このため、実行される正確なコードは実行時まで決定されません。
初期の実装や素朴な実装では、これは大きなパフォーマンスの低下となりますが、最新の JIT は、静的コンパイラを最適化することで得られる最高の状態に、興味をそそられるほど近くなります。(いくつかのフリンジケースでは、それよりもさらに優れています)。
仕事に適したツールがすべてです。どちらも 100% 優れているわけではありません。どちらのシステムも人によって作成されたものであり、欠陥があります。申し訳ありませんが、私たちは完璧なものを作っています。
邪魔にならないので動的型付けが好きですが、そうです、計画していなかった実行時エラーが忍び寄る可能性があります。静的型付けは前述のエラーを修正する可能性がありますが、(型付き言語の)初心者のプログラマーを定数文字と文字列の間でキャストしようとして夢中にさせます。