最新のプログラミング言語のほとんどで、Design by Contractのサポートが制限されているのはなぜですか?


40

私は最近、Design by Contract(DbC)を発見しましたが、コードを記述する非常に興味深い方法であることがわかりました。とりわけ、それは提供するように思われるでしょう:

  • より良いドキュメント。契約は文書であるため、契約が期限切れになることは不可能です。また、コントラクトはルーチンの動作を正確に指定するため、再利用のサポートに役立ちます。
  • 簡単なデバッグ。プログラムの実行はコントラクトが失敗した瞬間に停止するため、エラーは伝播できず、違反した特定のアサーションが強調表示されると考えられます。これにより、開発時およびメンテナンス時にサポートが提供されます。
  • より良い静的分析。DbCは基本的にHoareロジックの単なる実装であり、同じ原則を適用する必要があります。

それに比べて、コストはかなり小さいようです。

  • 余分な指タイプ。契約書を綴る必要があるため。
  • 契約書の作成に慣れるには、ある程度のトレーニングが必要です。

現在、主にPythonに精通しているため、実際には前提条件(不適切な入力に対して例外をスローするだけ)を作成することが可能であり、特定の事後条件を再度テストするためにアサーションを使用することもできます。しかし、「古い」または「結果」などの特定の機能をシミュレートすることは、最終的に非Pythonicと見なされる余分な魔法なしでは不可能です。(さらに、サポートを提供するライブラリがいくつかありますが、ほとんどの開発者がそうではないように、最終的にはそれらを使用するのは間違っているでしょう。)それは他のすべての言語でも同様の問題だと思います(もちろん、エッフェル)。

私の直感では、サポートの欠如はある種の慣行に対する拒絶の結果であるに違いないが、オンラインでの検索は有益ではなかったと教えてくれます。ほとんどの現代言語がほとんどサポートを提供していないように見える理由を誰かが明確にできるかどうか疑問に思っていますか?DbCに欠陥があるか、過度に高価ですか?それとも、エクストリームプログラミングやその他の方法論のために時代遅れになっているのでしょうか?


プログラムをテストするメリットもなしに、テスト駆動プログラミングを行うための非常に複雑な方法のように思えます。
ダン

3
@Danは、実際にはそうではなく、型システムの拡張と考えています。例えば、関数は整数の引数を取るだけでなく、契約上ゼロより大きくなければならない整数を取ります
-Carson63000

4
@Danコードコントラクトにより、実行する必要があるテストの数が大幅に削減されます。
宮坂

24
@ダン、むしろTDDは貧乏人の契約であり、その逆ではないと言いたいです。
SKロジック

動的言語では、オプションのフラグに基づいて、オブジェクトをコントラクトで「装飾」できます。環境フラグを使用して、既存のオブジェクトをコントラクトでオプションでモンキーパッチする実装あります。はい、サポートはネイティブではありませんが、追加は簡単です。テストハーネスにも同じことが当てはまります。これらはネイティブではありませんが、簡単に追加/記述できます。
レイノス

回答:


9

ほぼすべてのプログラミング言語でサポートされています。

必要なのは「アサーション」です。

これらは「if」ステートメントとして簡単にコーディングできます。

if (!assertion) then AssertionFailure();

これにより、入力制約のコードの先頭にそのようなアサーションを配置することにより、コントラクトを作成できます。戻り点のそれらは出力制約です。コード全体に不変条件を追加することもできます(ただし、実際には「契約による設計」の一部ではありません)。

だから、プログラマーは彼らをコーディングするのが面倒だからではなく、あなたがそれをできないからではない、と私は主張する。

コンパイル時のブール定数「チェック」を定義し、ステートメントを少し修正することで、ほとんどの言語でこれらをもう少し効率的にすることができます。

if (checking & !Assertion) then AssertionFailure();

構文が気に入らない場合は、マクロなどのさまざまな言語抽象化手法を使用できます。

いくつかの現代言語は、このための素晴らしい構文を提供します。それは、「現代の言語サポート」という意味です。それはサポートですが、かなり薄いです。

現代の言語のほとんどがあなたに与えないものは、「一時的な」アサーション(任意の前または後の状態[時間演算子「最終的に」)であり、本当に興味深いコントラクトを書きたい場合に必要です。IFステートメントは役に立ちませんここにいる。


アサートにアクセスするだけで問題になるのは、コマンドで事後条件をチェックする効果的な方法がないことです。これは、事後条件と事前条件の状態を比較する必要があることが多いからです(Eiffelはこれを「古い」と呼び、事後条件ルーチンに自動的に渡します) 。)Pythonでは、この機能はデコレーターを使用して簡単に再作成できますが、アサーションをオフにするときが来るとすぐに表示されます。
シーザーバウティスタ

エッフェルは実際に以前の状態をどれだけ保存しますか?(関数を分析することにより)停止の問題を解決せずにアクセス/変更できる部分を合理的に知ることができないため、完全なマシン状態を保存するか、色相として、その非常に浅い部分のみを保存する必要があります。私は後者を疑います。そして、これらは前提条件の前に単純なスカラー割り当てによって「シミュレート」できます。エッフェルがそうでないことを知ってうれしいです。
アイラバクスター

7
...エッフェルの仕組みを確認しました。「古い<exp>」は、関数への入り口での<exp>の値であるため、期待どおりに関数の入り口で浅いコピーを実行しています。あなたもそれらを行うことができます。私は、コンパイラが古い手ですべてこれを行うよりも便利ですが、ポイントは1つのである/プリ/ポストのための構文を実装した同意しますを手でこれにし、それは本当に難しいことではありません。怠け者のプログラマーに戻りました。
アイラバクスター

@IraBaxterいいえ。契約を実際のロジックから分離できる場合、コードはより単純になります。コンパイラは離れて契約し、コードを伝えることができる場合も、それはで重複を減らすことができますたくさん。たとえば、Dでは、インターフェイスまたはスーパークラスでコントラクトを宣言でき、関数のコードに関係なく、アサーションはすべての実装/拡張クラスに適用されます。たとえば、PythonまたはJavaのsuper場合、メソッド全体を呼び出して、重複することなくコントラクトのみをチェックしたい場合は、結果を破棄する必要があります。これは、クリーンなLSP準拠コードの実装に本当に役立ちます。
marstato

@marstato:言語でのサポートは良いことだとすでに同意しました。
イラバクスター

15

おっしゃるように、Design by Contract Eiffelの機能です。Eiffelは、以前はコミュニティで十分に尊敬されていたプログラミング言語の1つでしたが、一度も取り上げられたことはありません。

DbCは、最も一般的な言語ではありません。なぜなら、主流のプログラミングコミュニティが、コードに制約/期待を追加することはプログラマーに期待される「合理的な」ことだと受け入れたのは比較的最近のことです。プログラマーにとってユニットテストの重要性を理解するのは一般的なことであり、それはプログラマーが引数を検証してメリットを確認するためにコードを挿入することを受け入れるようになるまで浸透しました。しかし、10年前には、おそらくほとんどのプログラマーは「それは、あなたが常に大丈夫だと知っているもののための単なる余分な仕事だ」と言うでしょう。

今日、平均的な開発者のところに行って事後条件について話すと、彼らは熱心にうなずき、「OK、それは単体テストのようなものだ」と言うだろうと思います。そして、前提条件について話すと、「OK、それはパラメーター検証のようなもので、常にそうするわけではありませんが、わかっています、大丈夫だと思います...」 、彼らは「ジー、これはどのくらいのオーバーヘッドですか?さらに多くのバグをキャッチしますか?」と言い始めます。等

だから、DbCが非常に広く採用されるまでにはまだ長い道のりがあると思います。


主流のプログラマーであるOTOHは、かなり長い間アサーションを書くことに慣れていました。最新の主流言語に使用可能なプリプロセッサがないため、この優れたプラクティスは非効率になりましたが、CおよびC ++には依然として一般的です。現在、Microsoft Code Contracts(リリースビルド用のバイトコード書き換えであるAFAIKに基づく)でカムバックしています。
SKロジック

8

私の直感は、サポートの欠如は、ある種の練習の拒否の結果でなければならないことを教えてくれます...

偽。

これは設計上の慣例です。コード(エッフェルスタイル)で明示的に具体化するか、コード(ほとんどの言語)またはユニットテストで暗黙的に具体化できます。設計プラクティスが存在し、うまく機能しています。言語サポートは、マップ全体にあります。ただし、単体テストフレームワークでは多くの言語に存在します。

ほとんどの現代言語がほとんどサポートを提供していないように見える理由を誰かが明確にできるかどうか疑問に思っていますか?DbCに欠陥があるか、過度に高価ですか?

高いです。そして。さらに重要なこと、特定の言語は証明できないことがいくつかあります。たとえば、ループ終端はプログラミング言語では証明できません。「高次」証明機能が必要です。したがって、ある種の契約は技術的に表現できません。

それとも、エクストリームプログラミングやその他の方法論のために時代遅れになっているのでしょうか?

いや

ほとんどの場合、単体テストを使用して、DbCが満たされていることを示します。

Pythonについては、既に述べたように、DbCはいくつかの場所にあります。

  1. docstringおよびdocstringテストの結果。

  2. 入力と出力を検証するためのアサーション。

  3. 単体テスト。

さらに。

読み書き可能なプログラミングスタイルのツールを採用して、DbC情報を含み、クリーンなPythonと単体テストスクリプトを生成するドキュメントを作成できます。リテラシープログラミングアプローチを使用すると、契約書と完全なソースを含む素敵な文献を書くことができます。


固定有限シーケンスでの反復など、ループ終了の些細なケースを証明できます。それは一般的なループであり、簡単に終了することを示すことはできません(「興味深い」数学的推測の解決策を探している可能性があるため)。それが停止問題の本質です。
ドナルドフェローズ

+1。最も重要なポイントをカバーしたのはあなただけだと思います- there are some things which cannot be proven。正式な検証は素晴らしいかもしれませんが、すべてが検証可能というわけではありません!そのため、この機能は実際にプログラミング言語で実行できることを制限します!
ディパンメタ

@DonalFellows:一般的なケースは証明できないため、(a)高価で、(b)不完全であることが知られている多くの機能を組み込むことは困難です。この答えの私のポイントは、制限がある場合、これらのすべての機能を避け、一般的に正式な正当性証明の誤った期待を設定するのを避けることが簡単であるということです。(言語以外の)設計の演習として、多くの証明手法を使用できます(使用する必要があります)。
S.Lott

リリースビルドでコントラクトチェックがコンパイルされるC ++などの言語では、まったく高価ではありません。また、DBCを使用すると、合法な状態にあるプログラムの実行時チェックが少なくなるため、リリースコードがより軽量になりがちです。多数の関数が不正な状態をチェックし、適切にテストされたリリースビルドでその状態になってはならない場合にfalseを返す場所で見たgodawfulコードベースの数のカウントを失いました。
カイタン

6

ただ推測。「Design by Contract」はエッフェルの商標であるため、それほど人気が​​ない理由の一部かもしれません。


3

1つの仮説は、十分に大きな複雑なプログラム、特にターゲットが移動するプログラムの場合、契約自体の質量がプログラムコードだけの場合よりもバグが多く、デバッグが困難になる場合があります。他のパターンと同様に、収益の減少を超えて使用される可能性があるだけでなく、より的を絞った方法で使用された場合の明確な利点もあります。

もう1つの考えられる結論は、「マネージ言語」の人気が、選択したマネージ機能(契約による配列境界など)の契約による設計サポートの現在の証拠であるということです。


>契約自体の大部分は、これまで見たことのないプログラムコードだけよりもバグが多く、デバッグが困難になる場合があります。
カイタン

2

ほとんどの主流言語が言語にDbC機能を持たない理由は、それを実装することの費用対効果の比率が、言語実装者にとって高いことです。

この一方はすでに他の回答で検討されており、単体テストおよびその他のランタイムメカニズム(またはテンプレートメタプログラミングを使用したコンパイル時メカニズム)によって、DbCの利点の多くが既に得られます。したがって、利点はありますが、かなり控えめなものと考えられます。

もう1つの側面はコストです。DbCを既存の言語にレトロに適合させることは、重大な変更であり、起動するには非常に複雑です。古いコードを壊さずに言語に新しい構文を導入するのは困難です。既存の標準ライブラリを更新して、このような広範囲に及ぶ変更を使用すると、費用がかかります。したがって、既存の言語でDbC機能を実装するにはコストがかかると結論付けることができます。

また、テンプレートのほとんどの契約であり、したがってDbCにある程度関連する概念は、長年の作業が必要であると推定されるため、最新のC ++標準から削除されたことにも注意してください。言語に対するこれらの大きな、広範囲で抜本的な変更は、実装するには非常に困難です。


2

DbCは、コンパイル時に契約を確認できれば、契約に違反するプログラムを実行できないようにするために、より広範囲に使用されます。

コンパイラのサポートがなければ、「DbC」は「不変条件/仮定をチェックし、違反した場合は例外をスローする」ための単なる別名です。


それは停止の問題にぶつかりませんか?
シーザーバウティスタ

@Ceasarそれは異なります。一部の仮定はチェックできますが、他の仮定はチェックできません。たとえば、空のリストを引数として渡すことを回避したり、リストを返すことを可能にする型システムがあります。
インゴ

ナイスポイント(+1)ですが、「プログラミングの首謀者」のBertrand Meyer氏は、ランダムクラスの作成と契約違反のチェックの呼び出しについても言及しています。したがって、コンパイル時/実行時の混合アプローチですが、この手法があらゆる状況で機能するとは
思えません-Maksee

それはある程度真実ですが、例外ではなく壊滅的な障害でなければなりません(以下を参照)。DBCの主な利点は方法論であり、これにより実際にプログラムの設計が改善され、入力時に特定のメソッドが合法な状態でなければならないという保証により、内部ロジックの多くが簡素化されます。通常、契約に違反した場合に例外をスローすることはできません。プログラムがLEGALLY状態〜Xになる可能性がある場合は例外を使用する必要があり、クライアントコードはこれを処理する必要があります。契約では、〜Xは単に違法であると言われます。
カイタン

1

簡単な説明がありますが、ほとんどの人(プログラマーを含む)は、必要と思わない限り、余分な作業を望んでいません。安全性が非常に重要と考えられるアビオニクスプログラミングは、それなしではほとんどのプロジェクトを見たことがない。

しかし、Webサイト、デスクトップ、またはモバイルプログラミングを検討している場合、クラッシュや予期しない動作は悪いこととは見なされず、プログラマはバグを報告するときに余分な作業を避け、後で修正するだけで十分と考えられます。

これはおそらく、Adaは素晴らしい言語ですが、信頼性の高いシステムを構築したい場合、それが仕事に最適な言語であるため、コーディング作業が必要になるため、Adaが航空プログラミング業界以外で取り上げたことがないと思う理由ですAdaに基づく言語)。

C#のコントラクトライブラリによる設計は、Microsoftによる実験的なものであり、信頼性の高いソフトウェアを構築するのに非常に役立ちますが、市場で勢いをつけたことはありません。

アサーションは、事前/事後条件および不変条件の完全な機能サポートとは異なります。それらをエミュレートすることはできますが、適切にサポートされている言語/コンパイラは「抽象構文ツリー」分析を行い、単純に表明できない論理エラーをチェックします。

編集:私は検索を行いましたが、以下は役立つかもしれない関連する議論です:https : //stackoverflow.com/questions/4065001/are-there-any-provable-real-world-languages-scala


-2

主な理由は次のとおりです。

  1. 人気のない言語でのみ利用可能です
  2. 同じことを実際にやりたい人が既存のプログラミング言語で異なる方法で行うことができるので、それは不要です。
  3. 理解して使用することは困難です。適切に実行するには専門知識が必要なので、少数の人々がそれを実行します
  4. それを行うには大量のコードが必要です-プログラマは書く文字の量を最小限に抑えることを好みます-長いコードが必要な場合、何かが間違っているに違いありません
  5. 利点はそこにありません-それは価値があるようにするだけの十分なバグを見つけることができません

1
あなたの答えはよく議論されていません。利点はなく、大量のコードが必要であり、既存の言語で実行できるため不要であるという意見を述べるだけです(OPはこの問題に具体的に対処しました!)。
アンドレスF.

私はアサーションなどをそれに代わるものとして考えていません。これは、既存の言語でそれを行うには、正しい方法ではない(すなわち、それはまだ対処されていなかった)。
TP1

@ tp1、プログラマがタイピングを最小限に抑えたい場合、Javaほど冗長で雄弁なものに陥ることはありません。そして、はい、プログラミング自体は「適切に行うために」「専門知識」を必要とします。そのような知識を所有していない人は、コーディングを許可されるべきではありません。
SKロジック

@ Sk-logic:そうですね、メンバー関数からデータメンバーのメンバー関数に転送関数を書きたくないという理由だけで、世界の半分がオブジェクト指向を間違っているようです。私の経験では大きな問題です。これは、書き込む文字数を最小限に抑えることによって直接引き起こされます。
tp1

@ tp1、もし人々が本当にタイピングを最小限に抑えたいなら、彼らはオブジェクト指向さえ触らないでしょう。OOPは、Smalltalkのような最良の実装であっても、自然に雄弁です。私はそれが悪い特性であるとは言いません、雄弁は時々助けます。
SKロジック
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.