不変式とは何ですか、どのように使用できますか?プログラムで使用したことがありますか?


48

私はCoders at Workを読んでいますが、その中には不変条件について多くの話があります。私が理解した限りでは、不変式とは式の前後両方に当てはまる条件です。Logicコースを正しく覚えていれば、ループが正しいことを証明するのに役立ちます。

私の説明は正しいですか、何か見落としていませんか?プログラムでそれらを使用したことがありますか?もしそうなら、彼らはどのように利益を得ましたか?



@Robert Harvey:ええ、実際に読んだだけです。しかし、不変式は、何かを証明しようとしているときにのみ有用であるように思えます。これは正しいですか?
ギャブリン

それが私の理解です。プログラムの正当性を証明するために、プログラムについて推論しようとしているとき。
ロバートハーベイ

3
@ user9094:アサーションは、実行時の特定のポイントで何かが真であるという宣言であり、コードで表されます。不変式とは、適用される場合は常に真であり、コード自体には表されないステートメント(十分に根拠のあるもの)です。
デビッドソーンリー

1
不変式は正しさを証明するのに実際に役立ちますが、その場合に限定されません。また、防御的なプログラミングやデバッグ中にも役立ちます。彼らはあなたのコードが正しいことを証明するのを助けるだけでなく、コードについての理由を助け、起源に近いバグの場所を見つけるのを助けます。
奇数思考

回答:


41

OOPでは、不変式は、プログラムが有効であるためにオブジェクトの存続期間中、常に真でなければならない一連のアサーションです。オブジェクトがその状態を変更するメソッドを現在実行していないときはいつでも、コンストラクタの終わりからデストラクタの始まりまで成立するはずです。

不変式の例としては、2つのメンバー変数の正確に1つがnullである必要があります。または、一方に特定の値がある場合、もう一方に許可される値のセットはthisまたはthatです...

オブジェクトのメンバー関数を使用して、不変式が保持されていることを確認することもあります。そうでない場合は、アサートが発生します。そして、このメソッドは、オブジェクトを変更する各メソッドの開始および終了時に呼び出されます(C ++では、これは1行のみです...)


11
不変条件に言及するための+1は、実行メソッドの途中で真である必要はありません。
奇数思考

1
@Oddthinking可能な限りそれを避けるのが最善です。不変式の状態になり、戻る前にすべてを正しく復元するのを忘れることは簡単です。例外も問題を引き起こす可能性があります。
アレクサンダー

3
@Alexander:自明でない不変式の場合、回避することはほとんど不可能です。回答で説明されているように、メソッド内の複数の変数を更新する必要がある場合は、1つだけが更新され、不変式がfalseになるポイントがあります。新しいコードを追加せずに適切なコードを作成するには、十分な制約があります。
オッドシンク

@Oddthinkingええ、それはしばしばかなり避けられないものです。しかし、たとえば、論理的に一緒に属する変数のグループ(たとえば、配列、および配列内の「選択された」項目のインデックス)がある場合、おそらくそれらを型に抽出する価値があります。そこから、配列または型の変異は、その型の新しいインスタンスの単一の割り当てとして表現できます
アレクサンダー

13

さて、このスレッドで見ているものはすべて素晴らしいですが、仕事で私にとって非常に役立つ「不変式」の定義があります。

不変式とは、プログラムの実行を通じて従わなければならない論理的な規則であり、人間には伝達できますが、コンパイラには伝達できません。

この定義は、条件を2つのグループに分割するので役立ちます:コンパイラーが強制的に信頼できるものと、バグを導入せずにコードベースと対話するために文書化、議論、コメント、または貢献者に伝達する必要があるもの。

また、この定義は、「不変式が悪い」という一般化を使用できるため便利です。

例として、マニュアルトランスミッション車のシフターは、不変条件を回避するように設計されています。必要に応じて、ギアごとに1つのレバーを持つトランスミッションを構築できます。このレバーは、前方(「係合」)または後方(「係合解除」)にすることができます。そのようなシステムでは、「不変式」を作成しました。

「別のギアが噛み合う前に、現在噛み合っているギアを外すことが重要です。2つのギアを同時に噛み合わせると、機械的ストレスが発生し、トランスミッションが引き裂かれます。

そして、だらしない運転で壊れたトランスミッションを非難するかもしれません。しかし、現代の車は、ギアの間を旋回する1本のスティックを使用しています。現代のスティックシフト車では、同時に2つのギアを噛み合わせることができないように設計されています。

このように、論理規則に違反する方法でそれ自体を機械的に構成することを許可しないため、伝送は「不変式を除去する」ように設計されていると言えます。

コードから削除するこの種のすべての不変式は、コードを操作する認知的負荷を軽減するため、改善されます。


1
不変式が、プログラムの実行中に従う必要のある論理規則であり、論理規則が、2つのギアが同時にかみ合わないということであれば、2つのギアが同時にかからないという不変式ではない時間?この不変式がなければ、トランスミッションは同時に2つのギアになり、それ自体がバラバラになります。まず、単一のスティックシフターは実際にその不変条件を強制していませんか?第二に、なぜ不変式は本質的に良いのか悪いのか?
ダスティンクリーブランド

1
車のギアとの比較は私にとって非常に明確です。ありがとう!
マレッキー

「不変式とは、プログラムの実行中に従わなければならない論理的なルールであり、人間には伝えることができますが、コンパイラには伝えられません。」-私はこれがとても好きで、簡潔で覚えやすい。
ゼロナイト

@DustinClevelandこの例では、スティックシフトの背後にあるメカニズムはルールを「強制」する「コンパイラ」であり、一方、そうでなければインシデントを引き起こす可能性のあるドライバーは、多くのクライアントのうちの1つであり、 「文書化、議論、コメント、またはその他の方法で伝達された」。
エバーナード

素晴らしい説明!あなたのコードに不変式を含めるのが悪い習慣である理由についての理解を今私は本当に理解しています。
ベンCワン

3

不変式(常識)は、ある時点で、またはプログラムの実行中に常に真である必要がある条件を意味します。たとえば、PreConditionsとPostConditionsを使用して、関数が呼び出されたときと戻るときに真でなければならない条件をアサートできます。オブジェクト不変式を使用して、オブジェクトが存在する間ずっと有効な状態でなければならないことをアサートできます。これは、契約原則による設計です。
コード内のチェックを使用して非公式に不変式を使用しました。しかし最近では、不変式を直接サポートする.Netのコードコントラクトライブラリで遊んでいます。


3

Coders At Workからの次の引用に基づいて...

しかし、それが維持している不変式を知ると、ああ、その不変式を維持すれば、ログ検索時間が得られることがわかります。

...私は「不変」=「望ましい効果を保証するために維持したい条件」を推測します。

不変式には微妙に異なる2つの感覚があるようです。

  1. 同じままの何か。
  2. 目標Xを達成するために同じものを維持しようとしているもの(上記の「ログ検索時間」など)。

1はアサーションのようなものです。2は、正確性、パフォーマンス、またはその他の特性を証明するためのツールのようなものです。2の例については、Wikipediaの記事を参照してください(MUパズルの解の正確性を証明します)。

実際、不変量の第3の意味は次のとおりです。

.3。プログラム(またはモジュールまたは機能)が行うべきこと。言い換えれば、その目的。

同じCoders At Workインタビューから:

しかし、大きなソフトウェアを管理しやすくするのは、それが何をすべきであり、どのようなことが真実であると想定されるかについて、いくつかのグローバルな不変式または大局的な記述を持っていることです。


1

不変式は、プログラムのロジックを決定するために使用できるルールまたは仮定のようなものです。

たとえば、ユーザーアカウントを追跡するソフトウェアアプリケーションがあるとします。ユーザーが複数のアカウントを持つこともできますが、何らかの理由でユーザーのメインアカウントと「エイリアス」アカウントを区別する必要があるとします。

これはDBレコードまたは他の何かかもしれませんが、ここでは各ユーザーアカウントがクラスオブジェクトによって表されると仮定します。

クラスuserAccount {private char * pUserName; private char * pParentAccountUserName;

...}

不変条件は、pParentAccountUserNameがNULLまたは空の場合、このオブジェクトが親アカウントであるという仮定かもしれません。この不変式を使用して、さまざまなタイプのアカウントを区別できます。おそらく、さまざまな種類のユーザーアカウントを区別するためのより良い方法があるので、これはインバリアントがどのように使用されるかを示す例にすぎないことに留意してください。


不変条件は、プログラムの状態をチェックします。それらは設計上の決定ではありません。
ザビエルノード

3
不変式は何もチェックしません。プログラムの状態をチェックして、不変式がTRUEまたはFALSEであるかどうかを確認できますが、不変式自体は何もしません。
ペムダス

2
通常、C ++では、メンバーxが25未満で0を超えている必要があるなど、何らかのクラス不変性が見られます。これが不変です。その不変式に対するチェックはアサーションです。上記の例では、不変式は、pParentAccountUserNameがNULLまたは空の場合、親アカウントです。不変条件は、設計上の決定です。
ペムダス

pParentAccountUserNameがNULLまたは空の場合、このオブジェクトが親アカウントであることをどのように確認しますか?ステートメントは、null /空の値が何を表すかを定義するだけです。不変条件は、システムがそれに準拠することです。つまり、pParentAccountUserNameは、親アカウントである場合にのみnullまたは空にすることができます。それは微妙な違いです。
キャメロン14

1

物理学の背景から言えば、物理学には不変量があります。不変量は、本質的に計算/シミュレーション全体を通して変化しない量です。たとえば、物理学では、閉じたシステムの場合、総エネルギーが節約されます。または、物理学でも、2つの粒子が衝突する場合、結果のフラグメントには、開始時のエネルギーと正確に同じ運動量(ベクトル量)が含まれている必要があります。通常、結果を完全に指定するのに十分な不変式はありません。たとえば、2粒子衝突では、4つの不変量、3つの運動量成分、およびエネルギー成分がありますが、システムには6つの自由度があります(その状態を表す6つの数値)。不変量は丸め誤差内で保存されるべきですが、それらの保存は解が正しいことを証明しません。

したがって、通常、これらのことは健全性チェックとして重要ですが、それ自体では正当性を証明できません。


1
-1物理学の不変式は異なります。ソリューションの計算は、アルゴリズムが正しいことを証明することとは異なります。後者の場合、不変式正しさ証明できます。
aaronasterling
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.