web-dev-qa-db-ja.com

アサーションと比較して、scala)の仮定の意味は何ですか?

Scalaは、assertrequireassumeの3種類のアサーションを定義しているようです。

私が理解できる限り、requireの(一般的なアサーションと比較した)違いは、入力(引数、着信メッセージなど)をチェックするためのものであるということです。そして、assumeの意味は何ですか?

45
Ivan

Predef.scalaのコードを見ると、3つすべてが非常によく似た仕事をしていることがわかります。

def assert(assertion: Boolean) { 
  if (!assertion) 
    throw new Java.lang.AssertionError("assertion failed") 
} 

def assume(assumption: Boolean) { 
  if (!assumption) 
    throw new Java.lang.AssertionError("assumption failed") 
} 

def require(requirement: Boolean) { 
  if (!requirement) 
    throw new IllegalArgumentException("requirement failed") 
} 

レポートの目的で追加の引数を取るバージョンもあります( http://harrah.github.com/browse/samples/library/scala/Predef.scala.html を参照)。

違いは、スローする例外タイプと生成されるエラーメッセージにあります。

ただし、静的チェッカーは3つすべてを異なる方法で処理できます。 assertは静的チェックが証明しようとする条件を指定することを目的としており、assumeはチェッカーが保持すると想定する条件に使用され、requireは、呼び出し元が確認する必要のある条件を指定します。静的チェッカーがassertの違反を検出した場合、コード内のエラーと見なしますが、requireに違反した場合、呼び出し元に障害があると見なします。

49
Adam Zalcman

違い

Assert()とassume()の違いは

  • assert()は、不変条件を文書化して動的にチェックする方法ですが、
  • 仮定()は静的分析ツールによって消費されることを目的としています

Assert()の意図されたコンシューマー/コンテキストは、Scala JUnitテストなどのテストですが、assume()のそれは「pre-の契約による設計スタイルの仕様の手段として」です。そして、これらの仕様が静的分析ツールによって消費されることを意図した、関数の事後条件」( scaladoc から抜粋)。

静解析/モデル検査

静的分析のコンテキストでは、Adam Zalcmanが指摘しているように、assert()はグローバル不変条件をチェックするためのall-execution-pathsアサーションであり、assume()はローカルで動作してアナライザーが必要とするチェックの量を削減します。行う。仮定()は、分割統治法のコンテキストで使用されます。分割統治メカニズムは、プログラムのすべてのパスをチェックしようとしたときに発生する状態爆発の問題に対処するために、モデルチェッカーがメソッドについて何かを仮定するのに役立ちます。かかる場合があります。たとえば、プログラムの設計で関数f1(n1:Int、n2:Int)がn2 <n1に渡されることは決してないことがわかっている場合、この仮定を明示的に示すと、アナライザーが多くの組み合わせをチェックする必要がなくなります。 n1とn2の。

実際には

実際には、そのようなプログラム全体のモデルチェッカーはまだほとんど理論であるため、scalaコンパイラーとインタープリターが何をするかを見てみましょう。

  1. 実行時にassume()式とassert()式の両方がチェックされます
  2. -Xdisable-assertionsは、assume()とassert()の両方のチェックを無効にします

もっと

このトピックに関する優れたscaladocの詳細:

アサーション

assert関数のセットは、コード内の不変条件を文書化して動的にチェックする方法として使用するために提供されています。コマンドライン引数-Xdisable-assertionsscalaコマンドに指定することにより、実行時にアサートステートメントを省略できます。

静的分析ツールでの使用を目的としたassertのバリアントも提供されています:assumerequire、およびensuringrequireとensureingは、静的分析ツールでこれらの仕様を使用できるようにすることを目的として、関数の事前条件と事後条件の契約による設計スタイルの仕様の手段として使用することを目的としています。例えば、

def addNaturals(nats: List[Int]): Int = {
  require(nats forall (_ >= 0), "List contains negative numbers")
  nats.foldLeft(0)(_ + _)
} ensuring(_ >= 0)

AddNaturalsの宣言は、渡される整数のリストには自然数(つまり、非負)のみが含まれている必要があり、返される結果も自然になることを示しています。 requireはassertとは異なり、条件が失敗した場合、addNaturals自体で論理エラーが発生したのではなく、関数の呼び出し元が責任を負います。 suresは、関数が戻り値に関して提供している保証を宣言するアサートの形式です。 )

19
vijucat

私は2番目のアダムスの答えです、ここにいくつかの小さな追加があります:

assumeに違反すると、検証ツールはパスをサイレントに削除します。つまり、パスをこれ以上深く追跡しません。

したがって、assumeは事前条件を定式化するために、assertは事後条件を定式化するためによく使用されます。

これらの概念は、多くのツールで使用されています。コンコリックテストツール [〜#〜] klee [〜#〜] 、ソフトウェアで制限されたモデル検査ツール [〜#〜] cbmc [〜#〜] および- [〜#〜] llbmc [〜#〜] 、そして部分的には抽象解釈に基づく静的コード分析ツールによっても。記事 共通点を見つける:選択、主張、仮定 これらの概念を紹介し、それらを標準化しようとします。

5
DaveFar