What is the meaning of an assumption in scala compared to an assertion?

后端 未结 3 576
悲哀的现实
悲哀的现实 2021-01-31 07:44

Scala seems to define 3 kinds of assertions: assert, require and assume.

As far as I can understand, the difference (compared to a

3条回答
  •  盖世英雄少女心
    2021-01-31 08:26

    The difference

    The difference between assert() and assume() is that

    • assert() is a way to document and dynamically check invariants, while
    • assume() is intended to be consumed by static analysis tools

    The intended consumer / context of assert() is testing, such as a Scala JUnit test, while that of assume() is "as a means of design-by-contract style specification of pre- and post-conditions on functions, with the intention that these specifications could be consumed by a static analysis tool" (excerpted from the scaladoc).

    Static analysis / model checking

    In the context of static analysis, as Adam Zalcman has pointed out, assert() is an all-execution-paths assertion, to check a global invariant, while assume() works locally to pare down the amount of checking that the analyzer needs to do. assume() is used in the context of assume-guarantee reasoning, which is a divide and conquer mechanism to help model checkers assume something about the method so as to tackle the state explosion problem that arises when one attempts to check all paths that the program may take. For example, if you knew that in the design of your program, a function f1(n1 : Int, n2:Int) is NEVER passed n2 < n1, then stating this assumption explicitly would help the analyzer not have to check a LOT of combinations of n1 and n2.

    In practice

    In practice, since such whole-program model checkers are still mostly theory, let's look at what the scala compiler and interpreter does:

    1. both assume() and assert() expressions are checked at runtime
    2. -Xdisable-assertions disables both assume() and assert() checking

    More

    More from the excellent scaladoc on this topic:

    Assertions

    A set of assert functions are provided for use as a way to document and dynamically check invariants in code. assert statements can be elided at runtime by providing the command line argument -Xdisable-assertions to the scala command.

    Variants of assert intended for use with static analysis tools are also provided: assume, require and ensuring. require and ensuring are intended for use as a means of design-by-contract style specification of pre- and post-conditions on functions, with the intention that these specifications could be consumed by a static analysis tool. For instance,

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

    The declaration of addNaturals states that the list of integers passed should only contain natural numbers (i.e. non-negative), and that the result returned will also be natural. require is distinct from assert in that if the condition fails, then the caller of the function is to blame rather than a logical error having been made within addNaturals itself. ensures is a form of assert that declares the guarantee the function is providing with regards to it's return value. )

提交回复
热议问题