JavaScript:The Good PartsによるDouglas Crockfordの継承の章で、
古典的な継承のもう1つの利点は、型のシステムの仕様が含まれることです。これにより、プログラマーは明示的なキャスト操作を記述する必要がなくなります。これは、キャストすると型システムの安全性の利点が失われるため、非常に良いことです。
まず第一に、実際には安全とは何ですか?データの破損、ハッカー、システムの誤動作などに対する保護?
タイプシステムの安全上の利点は何ですか?これらの安全上の利点を提供することを可能にするタイプシステムの違いは何ですか?
型システムは違法プログラムを排除します。次のPythonコードを検討してください。
a = 'foo'
b = True
c = a / b
Pythonでは、このプログラムは失敗します。例外をスローします。 Java、C#、- Haskell などの言語では、これは合法的なプログラムでさえありません。これらのエラーは、一連の入力プログラムでは不可能なので、完全に回避します。
同様に、より良い型システムはより多くのエラーを除外します。超高度な型システムにジャンプすると、次のようになります。
Definition divide x (y : {x : integer | x /= 0}) = x / y
型システムは、0による除算エラーがないことを保証します。
これは、タイプのシステムが防止できるエラーの簡単なリストです
また、これはcompile時でもあることを覚えておいてください。型エラーを単にチェックするために100%のコードカバレッジでテストを記述する必要はありません。コンパイラーがそれを行うだけです:)
では、すべての型システムの中で最も単純な 型付きラムダ計算 を調べてみましょう。
基本的に2つのタイプがあり、
Type = Unit | Type -> Type
そして、すべての用語は変数、ラムダ、またはアプリケーションのいずれかです。これに基づいて、適切にタイプされたプログラムが終了することを証明できます。プログラムがスタックしたり、永久にループしたりすることは決してありません。これは真実ではないため、通常のラムダ計算では証明できません。
これについて考えてみましょう。型システムを使用して、プログラムが永久にループしないことを保証できます。
動的型システムは、静的型システムと同じ保証を提供できますが、コンパイル時ではなく実行時です。実際には、ランタイムなので、実際にはより多くの情報を提供できます。ただし、特に終了などの静的プロパティについては、いくつかの保証が失われます。
そのため、動的型は特定のプログラムを除外せず、例外をスローするなど、不正なプログラムを明確に定義されたアクションにルーティングします。
つまり、型システムは特定のプログラムを除外するということです。プログラムの多くは何らかの方法で壊れているため、型システムではこれらの壊れたプログラムを回避しています。
現実そのものがタイプされています。ウェイトに長さを追加することはできません。また、メートルにフィートを追加することもできますが(どちらも長さの単位です)、2つのうち少なくとも1つをスケーリングする必要があります。そうしないと、あなたの火星ミッションが文字通りかなりクラッシュする可能性があります。
タイプセーフシステムでは、異なる単位で表された2つの長さを追加すると、エラーになるか、自動キャストが発生します。
型システムを使用すると、単純なコーディングエラーを回避したり、コンパイラーがそれらのエラーをキャッチできるようになります。
たとえば、JavaScriptとPythonでは、次の問題が実行時にのみ検出されることがよくあります。テストの条件によっては、条件の品質/希少度が実際に本番環境になる可能性があります。
if (someRareCondition)
a = 1
else
a = {1, 2, 3}
// 10 lines below
k = a.length
強く型付けされた言語では、a
が配列であることを明示的に示す必要があり、整数を割り当てることはできません。このようにして、a
がlength
を持たない可能性はほとんどありません。
ソフトウェア開発サイクルの早い段階でエラーをキャッチできるほど、修正にかかる費用が少なくなります。最大のクライアント、またはすべてのクライアントがデータを失う原因となるエラーを検討してください。このようなエラーは、実際の顧客がデータを失った後にのみ検出された場合、会社の終わりになる可能性があります。このバグを見つけて修正する方が明らかにコストが低くなりますbefore運用環境に移動します。
費用がかからないエラーでも、テスターが関与していると、プログラマーがエラーを見つけて修正できる場合よりも多くの時間とエネルギーが費やされます。他のプログラマーがソース管理に依存するソフトウェアを構築できるソース管理にチェックインされない場合は、より安価です。型の安全性により、特定の種類のエラーがコンパイルされるのを防ぐことができるため、これらのエラーによる潜在的なコストのほとんどすべてを排除できます。
しかし、それだけではありません。動的言語でプログラムする人なら誰でも言うように、プログラムをコンパイルするだけで、細かい部分まで気にせずにプログラムの一部を試すことができるといい場合があります。安全性と利便性の間にはトレードオフがあります。ユニットテストは動的言語を使用するリスクの一部を軽減できますが、優れたユニットテストの作成と維持には独自のコストがあり、タイプセーフな言語を使用する場合よりも高くなる可能性があります。
実験している場合、コードが1回だけ使用される場合(1回限りのレポートなど)、ユニットテストを作成する必要がない場合は、動的言語がおそらく最適です。あなたのために。大規模なアプリケーションがあり、残りの部分を壊さずに1つの部分を変更したい場合、タイプセーフは命の恩人です。タイプセーフティキャッチのエラーの種類は、リファクタリング時に人間が見落としたり間違ったりする傾向があるエラーの種類です。
はじめに
型安全性は、静的に型付けされた(コンパイルされた静的型チェック)および/またはランタイム(評価された動的型チェック)言語のいずれかで実現できます。 Wikipedia a '...strong type systemによると、ランタイムがチェックされていない可能性がないものとして説明されていますタイプエラー(ed Luca Cardelli)。他の執筆では、チェックされていないランタイムエラーがないことを安全またはタイプセーフと呼んでいます...」
安全性-静的型チェック
古典的には、型の安全性は、コンパイル時に型の不一致を検出するように設計されたC、C++、Haskellなどの言語における静的型付けと同義です。これには、プログラムの実行時に未定義またはエラーが発生しやすい状況を回避できるという利点があります。これは、ポインタタイプが不一致になるリスクがある場合、たとえば、検出されない場合に壊滅的な結果につながる可能性がある状況では、非常に貴重です。この意味で、静的型付けはメモリの安全性と同義と見なされます。
ただし、静的型付けは完全に安全ではありませんが、安全性を高めますです。静的に型付けされたシステムでさえ、壊滅的な結果をもたらす可能性があります。多くの専門家は、静的型付けを使用して、より堅牢でエラーが発生しにくい(ミッションクリティカルな)システムを作成できると考えています。
静的型付け言語can doubleとfloat型の不一致または切り捨て、または整数型とfloat型の不一致が原因で発生する可能性がある、データの損失や数値計算の精度の損失のリスクを減らすのに役立ちます。
静的型付け言語を使用すると、効率と実行速度が向上します。ランタイムは、実行中にタイプを判別する必要がないことからメリットを得ます。
安全性-ランタイムタイプチェック
たとえば、Erlangは、仮想マシンで実行される型宣言型の動的型チェック済み言語です。 Erlangコードはバイトコンパイルできます。 Erlangは、おそらく最も重要なミッションクリティカルでフォールトトレラントな言語と考えられており、Erlangには 9の信頼性 (99.9999999%または年間31.5ミリ秒以下)があると報告されています。
Common LISPなどの特定の言語は静的に型付けされていませんが、必要に応じて型を宣言して、速度と効率を向上させることができます。また、Pythonなどの広く使用されているインタプリタ言語の多くは、評価ループの下にあり、CやC++などの静的型付き言語で記述されています。 Commom LISPとPythonはどちらも、上記の定義ではタイプセーフと見なされます。
型システムについてまだ言及されていない利点の1つは、多くのプログラムが記述よりも多く読み取られるという事実を中心としており、多くの場合、型システムでは、簡潔で簡単にできる方法で多くの情報を指定できる場合があります。コードを読んでいる人によって消化されました。パラメータタイプは説明コメントの代わりにはなりませんが、ほとんどの人はそれを読む方が速くわかります。またはDistance As Int32
読むよりも「距離は整数+/- 2147483647でなければなりません」;分数を渡すと、一貫性のない結果が生じる可能性があります。」さらに、パラメータタイプは、APIの特定の実装が行うことと、呼び出し元が依存する資格があるものとの間のギャップを減らすのに役立ちます。たとえば、APIの特定のJavaScript実装が文字列を数値形式に強制する方法でパラメータを使用する場合、呼び出し元がそのような動作に依存できるかどうか、または文字列が指定されている場合にAPIの他の実装が誤動作する可能性があるかどうかは不明です。パラメータがDouble
として指定されているメソッドがあると文字列値は渡される前に呼び出し元によって強制される必要があることを明確にします。Double
を受け入れるオーバーロードを持つメソッドとString
を受け入れる別のメソッドがあると、文字列を保持する呼び出し元がそのようにそれらを渡すことが許可されることがいくらか明確になります。
型システムの安全上の利点は失われます。
まず第一に、実際には安全とは何ですか?データの破損、ハッカー、システムの誤動作などに対する保護?
タイプシステムの安全上の利点は何ですか?これらの安全上の利点を提供することを可能にするタイプシステムの違いは何ですか?
型システムにはそのような否定的な見方があるように感じます。型システムは、エラーがないことを証明することではなく、保証を行うことです。後者は型システムの結果です。プログラミング言語の型システムは、プログラムがなんらかの仕様を満たしていることを証明するコンパイル時の方法です。
型としてエンコードできる仕様の種類は、言語、またはより直接的には言語の型システムの強さに依存します。
最も基本的な種類の仕様は、関数の入出力動作と関数本体の内部の有効性に関する保証です。関数ヘッダーを検討する
f : (Int,Int) -> String
優れた型システムは、fが評価時にIntのペアを生成するオブジェクトにのみ適用され、fが常に文字列を生成することを保証します。
If-thenブロックのような言語の一部のステートメントには、入力/出力動作がありません。ここで型システムは、ブロック内の各宣言またはステートメントが有効であることを保証します。つまり、正しい種類のオブジェクトに操作を適用します。これらの保証は構成可能です。
また、これは一種のメモリ安全条件を提供します。あなたが扱っている見積もりはキャストに関するものです。 32ビットIntを64ビットIntにキャストする場合のように、キャストが適切な場合もあります。ただし、一般的には、型システムがクラッシュします。
検討する
Foo x = new Foo(3,4,5,6);
f((Int)x,(Int)x);
キャストのため、xはIntに変換されるため、技術的には上記の型チェックを行います。ただし、タイプチェックの目的は実際には無効です。
BがAのサブタイプ(またはサブオブジェクト)でない限り、ケースの前のxがタイプBである場合、キャスト(A)xを無効にすることが、タイプタイプシステムを変える可能性があります。サブタイピング理論の考え方は、セキュリティで使用されています整数オーバーフロー/アンダーフロー攻撃の可能性を取り除くため。
概要
型システムは、プログラムがある種の仕様を満たしていることを証明する方法です。型システムが提供できる利点は、使用される型システムの強さによって異なります。
まず第一に、実際には安全とは何ですか?データの破損、ハッカー、システムの誤動作などに対する保護?
他のすべての答えなど。一般に、「タイプセーフ」とは、コンパイラが正常にコンパイルしたプログラムにタイプエラーが含まれないことを意味します。
さて、型エラーとは何ですか?原則として、望ましくないプロパティを型エラーとして指定できます。一部の型システムは、プログラムにそのようなエラーがないことを静的に保証できます。
上記の「プロパティ」とは、たとえば「すべてのインデックスが配列の境界内にある」など、プログラムに適用されるある種の論理命題を意味します。その他のタイプのプロパティには、「すべての遅延ポインタは有効」、「このプログラムはI/Oを実行しない」、「このプログラムは/ dev/nullに対してのみI/Oを実行する」などがあります。プロパティは、タイプシステムの表現力に応じて、この方法で指定およびタイプチェックできます。
依存型システムは、最も一般的な型システムの1つであり、これを使用すると、ほとんどすべてのプロパティを強制できます。ただし、洗練されたプロパティは incompletenessGödel の厚意により提供されるため、必ずしもそうするのは簡単ではありません。