質問: プログラムで任意のコードの安全性を評価することは可能ですか? 最近、安全なコードについて多くのことを考えています。スレッドセーフ。メモリセーフ。 segfaultセーフで自分の顔を爆発させない。ただし、質問を明確にするために、rustの安全モデルを定義として使用します。多くの場合、rustがunsafeを必要とすることで証明されるように、並行性などの非常に合理的なプログラミングのアイデアがあるため、安全性を確保することは少し大きな問題ですcannotをrustに実装する場合、unsafeキーワードを使用しないでください。ロックを使用すると、同時実行を完全に安全にすることができます。 、ミューテックス、チャネル、メモリ分離、または何があるか、これにはunsafeを使用してrustの安全モデルの外で作業し、手動でコンパイラに保証する必要があります "ええ、私は自分のやっていることを知っています。これは安全ではないように見えますが、数学的には完全に安全であることを証明しました。"しかし通常、これは手動でこれらのもののモデルを作成し、それらが 定理証明者 で安全であることを証明することになります。コンピュータサイエンスの観点(可能か)と実用性の観点(宇宙の生命を奪うことになるか)の両方から、任意の言語で任意のコードを受け取り、それがそうであるかどうかを評価するプログラムを想像するのは合理的です錆びない」注意事項: これの簡単な解決策は、プログラムが停止しない可能性があることを指摘することです。そのため、 停止の問題 は失敗します。読者に提供されたプログラムが停止することが保証されているとしましょう 「任意の言語の任意のコード」が目標ですが、これはプログラムが選択された言語に慣れていることに依存していることはもちろん承知しています。
回答: 型システムは、正確性のいくつかの側面を自動的に検証できる証拠です。たとえば、rustの型システムは、参照が参照オブジェクトよりも長く存続しないこと、または参照オブジェクトが別のスレッドによって変更されていないことを証明できます。しかし、型システムはかなり制限されています: 彼らはすぐに決定可能性の問題にぶつかります。特に、型システム自体は決定可能である必要がありますが、実際の型システムの多くは誤ってturing completeです(テンプレートによるc++とrustトレイトのため))。また、プログラムの特定のプロパティ一般的に、プログラムが停止(または分岐)するかどうかを確認することはできません。 さらに、型システムは、理想的には線形時間ですばやく実行する必要があります。可能なすべての証明が型システムで取り上げられるべきではありません。例えば。プログラム全体の分析は通常避けられ、証明は単一のモジュールまたは関数に限定されます。 これらの制限があるため、型システムは検証が容易なかなり弱いプロパティのみを検証する傾向があります。関数が正しい型の値で呼び出されること。それでも表現力が大幅に制限されるため、回避策(goではinterface{}、c#ではdynamic、javaではobject、cではvoid*など)を使用するか、完全に回避する言語を使用することも一般的です静的型付け。検証するプロパティが強いほど、言語の表現力は低下します。 rustを作成した場合、正しいことが証明できなかったため、コンパイラが一見正しいコードを拒否する「コンパイラとの戦い」の瞬間を知っています。場合によっては、特定のプログラムをrustで表現することは不可能であることは、その正確性を証明できると確信している場合でも可能です。unsafeメカニズムrustまたはc#を使用すると、型システムの制限を回避できます。場合によっては、チェックをランタイムに延期することも別のオプションになる可能性があります。ただし、無効なプログラムを拒否できない場合があります。 。これは定義の問題です。rustプログラムは、型システムに関する限りパニックは安全ですが、必ずしもプログラマーまたはユーザーの観点からではありません。言語は型システムと一緒に設計されています。新しい型システムが既存の言語に課されることはまれです(ただし、mypy、flow、typescriptなどを参照してください)。言語は、型システムに準拠するコードを簡単に記述できるようにします。型注釈を提供することによって、または制御フロー構造を証明するのが簡単なものを導入することによって。言語が異なれば、ソリューションも異なる場合があります。例えば。 javaには、rustの非final変数と同様に、1回だけ割り当てられるmut変数の概念があります。final int x; if (...) { ... } else { ... } dosomethingwith(x); javaには、すべてのパスが変数を割り当てるか、変数にアクセスする前に関数を終了するかを決定する型システムルールがあります。対照的に、rustは、宣言されているが設計されていない変数がないことでこの証明を簡略化しますが、制御フローステートメントから値を返すことができます。let x = if ... { ... } else { ... }; do_something_with(x) これは、割り当てを理解する上で非常にマイナーなポイントのように見えますが、明確なスコープは、生涯に関連する証明にとって非常に重要です。rustスタイルの型システムをjavaに適用する場合、それよりもはるかに大きな問題が発生します。javaオブジェクトにはライフタイムの注釈が付けられないため、&'static someclassまたはarc<dyn someclass>。これは結果として生じる証明を弱めます。javaには不変性のタイプレベルの概念もないため、&と&mutタイプを区別できません。オブジェクトをセルまたはセルとして扱う必要があります。ミューテックス、ただしこれはjavaが実際に提供するものよりも強力な保証を想定している場合があります(javaを変更すると、同期および揮発性でない限り、フィールドはスレッドセーフではありません)。最後に、rustには、javaスタイルの実装継承の概念はありません。tl; dr:型システムは定理を証明します。ただし、決定可能性の問題とパフォーマンスの問題によって制限されます。ターゲットの言語構文が必要な情報を提供しない場合や、セマンティクスに互換性がない場合があるため、1つの型システムを単純に別の言語に適用することはできません。