How do I format a string?
Question
How do I format a string?
Answer
As of version 3.7.3, Dafny has no built-in or library capability to convert values to strings or to format them.
There is only the print
statement that emits string representations of values to standard-out.
For now you will need to implement your own methods that convert values to strings, concatenating them to produce formatted strings.
Where do I put the reads clause in a subset type?
Question:
This example
// dafny Example.dfy
class A {
var x: string
}
type AA = a: A | a.x == "" witness * reads a
generates this error:
FAQReadsClause.dfy(6,37): Error: this symbol not expected in Dafny
1 parse errors detected in FAQReadsClause.dfy
but there is no obvious place to put a reads
clause.
Answer:
There is no place for the reads
clause because no such clause should be needed.
A type definition is not allowed to depend on a mutable field;
the predicate in the subset type must be pure.
The general idiom is to add a predicate, often named Valid()
, to a class that
reads its fields and returns true
if the class members are appropriately consistent.
Then call Valid()
in the pre- and post-conditions of methods and in
preconditions of functions and predicates. Here is an example:
class A {
var x: string
var y: string
predicate Valid() reads this {
|x| == |y|
}
}
method Test(a: A)
requires a.Valid()
requires a.x == ""
modifies a
ensures a.Valid()
{
assert a.Valid(); // That's correct thanks to the precondition.
a.x := "abc"; // Because |a.y| == 0, we broke the Valid() predicate
assert !a.Valid(); // But that's ok.
a.y := "bca";
assert a.Valid(); // Now Dafny can prove this
// The postcondition holds
}
The {:autocontracts}
attribute can be helpful here.
Note that the idiom using Valid()
above is similar to the use of class invariants in other
specification languages.
Can datatypes extend traits?
Question:
I heard a rumor of datatypes extending traits coming in the pipeline. How will that work? Will we be able to use is
and as
with such types?
Answer:
Yes, datatypes extending traits are coming (but not immediately).
The traits would need to be declared when the datatype is declared; the trait cannot be added later on.
is
and as
are possible.
What is the difference between a type and a newtype?
Question
One can define a subset type like this
type int8 = x: int | -128 <= x < 128
and a newtype like this
newtype nint8 = x | -128 <= x < 128
What is the difference?
Answer
In both cases, the values in the type are limited to the given range, but a newtype intends to define a whole new type that, although still based on integers and allowing integer operations, is not intended to be mixed with integers.
This is evident in the allowed conversions, as shown in this example code:
type int8 = x: int | -256 <= x < 256
newtype nint8 = x : int | -256 <= x < 256
method test(i: int, i8: int8, ni8: nint8) {
var j: int, j8: int8, nj8: nint8;
if -256 <= i < 256 { j8 := i; } // implicit conversion OK if in range
if -256 <= i < 256 { nj8 := i as nint8; } // explicit conversion required
j := i8; // always allowed
j := ni8 as int; // explicit conversion required
}
The other important characteristic of newtype
s is that they may have a different representation in the compilation target language.
Subset types are always represented in the same way as the base type. But a newtype may use a different representation.
For example, the newtype defined above might use a byte
representation in Java, whereas an int
is a BigInteger
.
The representation of a newtype can be set by the program author using the {:nativeType}
attribute.
Why can compiled modules contain but not import abstract modules?
Question
Why can compiled modules contain but not import abstract modules?
Answer
The question refers to code like this:
abstract module J {}
module K {
abstract module JJ {}
import J // ERROR
}
It is indeed the case that the abstract module JJ
can be declared in non-abstract module K
but the abstract module J
is not permitted to be imported.
This discrepancy is the subject of a proposed change to Dafny rules (cf. issue #2635).
In either cases, however, there are limits on what can be done with an abstract submodule. It is first of all not compiled as part of the enclosing module. Thus it can only be used as the subject of refinement.
That feature is described in the remainder of this FAQ.
The enclosing module may declare an abstract module A and also a non-abstract module B that refines A.
A refining module import (import D : C
) may only occur in an abstract module itself.
Generally speaking, suppose you have an underspecified module that is imported using ‘:’, as in
abstract module Interface {
function addSome(n: nat): nat
ensures addSome(n) > n
}
abstract module Mod {
import A : Interface
method m() {
assert 6 <= A.addSome(5);
}
}
Here A
is abstract because it stands for any concrete module that adheres to the interface declared in Interface
(note that the function addSome
has no body). Consequently Mod
must be abstract as well.
Interface
is not compilable, but it actually does not need to be declared abstract
.
Now we can implement a concrete version of Interface
:
module Implementation {
function addSome(n: nat): nat
ensures addSome(n) == n + 1
{
n + 1
}
}
Then we can implement the concrete module Mod2
as a refinement of the abstract module Mod
:
module Mod2 refines Mod {
import A = Implementation
...
}
Here the module Mod.A
, which is an unspecified refinement of Interface
inside of Mod
, is refined to be the concrete module
Implementation
inside of Mod2
, which is a refinement of Mod
.
Why does Dafny need an obvious assert?
Question:
Why does Dafny need the assert in this example:
lemma Foo<T>(s: seq<T>, p: seq<T> -> bool)
requires p(s[..|s|])
ensures p(s)
{
assert s[..|s|] == s;
}
Answer
Not all facts about built-in types are built-in to Dafny. Some, like this one, need to be asserted or otherwise provided as provable lemmas.
The reason is that trying to provide all seemingly obvious facts is both a never-ending chase and, importantly, can lead to trigger loops, proof instabilities, and overall poor performance. The importance of having proofs be stable and performance be generally fast outweighs building in all the properties of built-in types that might otherwise be reasonable.
Why do I need a witness clause when I define a subset type or newtype?
Question
Why do I need a witness clause in subtype definitions like
type A = s: int | Prime(x) witness 13
Answer
Dafny generally assumes that types are non-empty; the witness is an example value that is in the type, demonstrating that the type is non-empty.
There are defaults for the witness
clause, so you don’t always have to have one. The default value is some zero-equivalent value: 0
for int
based types, 0.0
for real
-based types,
empty sets, sequence and maps for those base types.
And, it is permitted to have possibly empty types by using a witness clause witness *
, but there are restrictions on the use of possibly empty types.
For instance, a declaration of a variable with a possibly-empty type will need an initializer,
if that variable is ever used, because Dafny requires variables to be ‘definitely assigned’ before being used.
The Reference Manual contains a discussion about witness clauses.
Can I access the members of an outer module from its inner module?
Question
Can I access the members of an outer module from its inner module?
module A {
const SIZE := 10
module B {
const MYSIZE := SIZE
}
}
Answer
No. The above example gives the error messages
FAQNestedModule.dfy(5,20): Error: unresolved identifier: SIZE
FAQNestedModule.dfy(5,10): Error: const field's type is not fully determined
FAQNestedModule.dfy(4,9): Error: not resolving module 'A' because there were errors in resolving its nested module 'B'
3 resolution/type errors detected in FAQNestedModule.dfy
From a module you may access your own nested modules. You may also access sibling modules and nested modules of sibling modules, but you need to import them. That includes sibling modules of a module’s own enclosing modules. You may not access members of enclosing modules, including members declared at the global level (which are members of an implicit top-level module that includes everything in the program).
In general, there is a dependency order among modules: a module depends on modules whose members it uses. A module depends on its own nested modules. A program cannot have circular dependencies: a module A cannot use members of module B if B (transitively) depends on A.
module A {
module B {
const S1 := 10
}
}
const S2 := 21
const S3 := C.D.A.B.S1 // OK
module C {
module D {
import A // OK - A is sibling of C
import A.B // OK
import E // OK - E is sibling of D
import E.F // OK
// import C // NOT OK - C is enclosing module
// import EE = C.E // NOT OK -- can't access enclosing module
// const X := S2 // NOT OK -- can't access top-level module
const Y := B.S1 // OK - B is imported module
}
module E {
module F {
}
}
}
What is -
on bitvectors?
Question
What is -
on bitvectors?
Answer
The -
operator for bit-vectors is subtraction or unary negation.
Unary negation, - b
is equivalent to 0 - b
.
This is not the same as complement, which is written as ! b
.
For example, the bv5
value equivalent to the natural number 13
is 01101
.
- The complement of this value is
10010
, which is18
. - The negation of this value is
10011
, which is19
.
In 2’s complement fixed-bit-width arithmetic, -x
is !x + 1
.
Is there a simple way to prove the termination of a recursive function?
Question
Is there a simple way to prove the termination of a recursive function?
Here is an example function:
datatype Dummy = State1 | State2
function WalkState(str: string, s: Dummy): string {
if str == [] then []
else if s.State1? then WalkState(str[1..], Dummy.State2)
else WalkState(str, Dummy.State1)
}
Answer
In general, to prove termination of any recursive structure, one needs to declare a
(well-founded) measure that decreases on each iteration or recursive invocation;
because a well-founded measure has no infinitely decreasing sequences, the recursion must eventually terminate.
In many cases, Dafny will deduce a satisfactory (provable) measure to apply by default.
But where it cannot, the user must supply such a measure. A user-supplied measure is
declared in a decreases
clause. Such a measure is a sequence of expressions, ordered lexicographically by the
termination metric for each data type; the details of the ordering are
explained in the reference manual section on Decreases Clause.
In the case of this example, the measure must be a combination of the length of the string,
which decreases (and is bounded by 0) in the else if branch and the state,
creating a measure in which Dummy.State1
is less than Dummy.State2
and so decreases in the
final else branch. So we can write
datatype Dummy = State1 | State2
function WalkState(str: string, s: Dummy): string
decreases |str|, if s.State2? then 1 else 0
{
if str == [] then []
else if s.State1? then WalkState(str[1..], Dummy.State2)
else WalkState(str, Dummy.State1)
}
which then proves without further user guidance.
Is there a way to use methods within expressions?
Question
Is there a way to use methods within expressions?
Answer
No. Dafny distinguishes statements and expressions. Statements are permitted to update variables and fields (that is, have side-effects); expressions are not allowed to do so. In general, methods may have side-effects and so Dafny does not allow methods in expressions. So you need to call each method in a statement of its own, using temporary local variables to record the results, and then formulate your expression.
If the methods in question do not have side-effects, they can be rewritten as functions or ‘function by method’ and then the syntax decribed above is fine.
If I have an assertion about an object (of class type) and a loop that doesn’t mention (read, modify) the object, why does dafny fail to establish the assertion after the loop?
Question
If I have an assertion about an object and a loop that doesn’t mention (read, modify) the class, why does dafny fail to establish the assertion after the loop?
Answer
The short answer is that you need an appropriate combination of modifies clauses and loop invariants to prove assertions about the end result of a loop.
In Dafny’s way of reasoning about a loop (which is typical of verifier systems), the loop invariant is the only thing you can assume at the top of every iteration. In other words, at the top of each loop iteration, it is as if all variables have arbitrary values, with the condition that the loop invariant is satisfied. Sometimes, the word havoc is used to describe this: the verifier havocs all variables, that is, gives all variables arbitrary values, and then assumes the loop invariant.
If that’s all the verifier did, life would be a pain, because you’d have to write a loop invariant about all variables in your program, even those that have nothing to do with the loop. The verifier actually does better. Instead of havocing all variables, it suffices to havoc the assignment targets within the body of the loop, including anything that might be modified by methods called in the loop body. That is, the verifier uses a simple syntactic scan of the loop body to see which variables may possibly be assigned, and then it havocs only those variables. This saves users from having to write loop invariants about all other variables. Only invariants about variables that are modified are needed.
What about the heap? For this purpose, the heap is considered to be one variable. So, the heap is either an assignment target of the loop or it isn’t. This means that if your loop body assigns to anything in the heap, the heap becomes an assignment target. Also, if the loop body allocates another object, that too is a change of the heap, so the heap becomes an assignment target. Furthermore, Dafny’s rule about a method is that a method is allowed to change the state of any object in the method’s modifies clause, and it is also allowed to allocate new objects and to modify their state. Therefore, if your loop body calls a method, then the heap may well become an assignment target.
So, then, does this mean your loop invariant needs to speak about everything in the heap whenever the heap is an assignment target of the loop?
Again, no. Loops in Dafny have modifies
clauses, just like methods do (and just like for methods,
newly allocated objects are implicitly included in those modifies
clauses).
It would be a pain to even have to write modifies
clauses for every loop,
so if a loop does not have an explicit modifies
clause, Dafny implicitly attaches
the modifies
clause of the enclosing method (or of the enclosing loop, in the case of nested loops).
This default behavior turns out to be right in almost all cases in practice,
which is why you normally don’t have to think about this issue.
But when it is not, you need to be explicit about the modifies
clause and the loop invariants.
In particular
- write a
modifies
clause for the loop that includes all objects whose fields might be assigned in the loop body (or listed in the modifies clauses of anything the loop body calls) - then write a loop invariant that includes assertions about any variable that is listed in the modifies clause or is an assignment target in the loop body. Very typically, the invariant will give a value for each havoced variable showing its relationship to the loop index.
For example, a loop that sets the elements of an array to some initial value might look like this:
method init(a: array<int>)
modifies a
ensures forall j | 0 <= j < a.Length :: a[j] == j
{
var i := 0;
while i < a.Length
modifies a
invariant 0 <= i <= a.Length && forall j | 0 <= j < i :: a[j] == j
{
a[i] := i;
i := i + 1;
}
}
Note the following points:
- The method specifies that it might modify the elements of the array
a
. - The loop says that it modifies the same array. In fact that modifies clause could be omitted because it would be inherited from the enclosing context.
- The loop also modifies
i
, but asi
is a local variable, it need not be listed in the modifies clause. - The loop also has an invariant, which has two conjuncts:
- One conjunct talks about the local variable
i
. Even thoughi
is not in the modifies clause it is an assignment target, so we need to say what is known about it (prior to the loop test). - The other conjunct talks about the elements of
a
, which depend oni
, that is, on how many iterations of the loop have been executed.
- One conjunct talks about the local variable
- After the loop, Dafny uses the loop invariant and the negation of the loop guard to conclude
i == a.Length
, and from that and the invariant, Dafny can prove the method’s postcondition.
Even when Dafny can infer an appropriate modifies clause, it does not infer loop invariants, so the user always needs to supply those.
Here is another example:
class Counter {
var n: nat
}
// print "hello" c.n times and then increment c.n
method PrintAndIncrement(c: Counter)
modifies c
ensures c.n == old(c.n) + 1
{
for _ := 0 to c.n
// To verify this method, the loop needs one of the following two lines:
invariant c.n == old(c.n)
modifies {} // empty modifies clause
{
PrintHello();
}
c.n := c.n + 1;
}
method PrintHello() {
print "hello\n";
}
The for-loop can be specified and the whole method verified in two different ways.
First, suppose we do not include a modifies clause in the loop specifications of the loop.
Then dafny will use the enclosing modifies clause, which allows changing the
state of c
. In order for the method body to know that the loop has not
changed c.n
, the loop needs the invariant c.n == old(c.n)
.
Alternatively, the loop can specify its own modifies clause,
modifies {}
, saying it modifies nothing. Then it follows directly that
c.n
does not change in the loop, so no invariant is needed to carry out the proof.
I can assert a condition right before a return, so why does the postcondition fail to verify?
Question
I can assert a condition right before a return, so why does the postcondition fail to verify?
Answer
There can be lots of reasons why a postcondition might fail to verify, but if you can prove the same predicate just before a return,
a typical reason is that there are other exit paths from the method or function. There might be other return
statements, but a
harder to spot exit path is the :-
let-or-fail assignment.
Here is a sketch of that kind of problem:
include "library/Wrappers.dfy"
method test(MyClass o) returns (r: Wrappers.Result<int>)
modifies o;
ensures o.ok == true;
{
o.ok := true;
o.data :- MyMethod(o);
assert o.ok;
return;
}
(This example uses the Result
type from the standard library. The include
directive in the example requires that you have a copy of the standard library in ./library
.)
This method can exit either through the return
at the end or through the failure return if a failure value is returned
from MyMethod
. That return happens before the assert
that is intended to do a pre-check of the postcondition; depending
on the action of MyMethod
, the target predicate may not be always true.
How can I combine sequences of different types?
Question
How can I combine sequences of different types?
Answer
It depends on the types. If the different types are subset types of a common base type, you can make a combined list of the base type. Similarly if the two types are classes (or traits) that extend a common trait, then you can combine sequences into a sequence of that trait. And since all classes extend the trait object
, that can be the common type.
Here is some sample code:
trait T {}
class A extends T {}
class B extends T {}
method m() {
var a: A := new A;
var sa: seq<A> := [ a ];
var b := new B;
var sb : seq<B> := [b ];
var st : seq<T> := sa + sb;
var so : seq<object> := sa + sb;
}
In fact, Dafny will generally infer a common type for you in the case of sequence concatentation.
How do I disambiguate module names?
Question
How do I disambiguate module names in an example like this:
module util {
const x: nat := 0
}
module java {
module util {
const y: nat := util.x
method test() { assert y == 0; }
}
}
Answer
There is no direct syntax to do what is wanted here.
If you have control of the names, perhaps some renaming or moving the top-level util
to be a sub-module of another module.
If this structure cannot be changed, then the following somewhat ugly code is a work-around:
module util {
const x: nat := 0
}
module util_ {
import util
}
module java {
module util {
import util_
const y: nat := util_.util.x
method test() { assert y == 0; }
}
}
There is discussion of defining syntax that names the top-level module, which would make an easy way to solve the above problem. See this issue.
A function seems to work just once. How do I get it to apply a bunch of times?
Question
A function seems to work just once. How do I get it to apply a bunch of times? Here is an example:
function Sum(s: seq<nat>): nat {
if |s| == 0 then 0
else s[0] + Sum(s[1..])
}
lemma Sum1(s: seq<nat>)
requires |s| == 1
ensures Sum(s) == s[0]
{
// trivial
}
lemma Sum2(s: seq<nat>)
requires |s| == 2
ensures Sum(s) == s[0] + s[1]
{
// Doesn't work. I need...
// Sum1(s[1..]);
}
lemma Sum3(s: seq<nat>)
requires |s| == 3
ensures Sum(s) == s[0] + s[1] + s[2]
{
// Doesn't work. I need...
// Sum2(s[1..]);
}
The latter two lemmas will not prove without uncommenting the application of the lemma for one less iteration. How can I get this to prove automatically?
Answer
Function bodies are transparent. That is, when there is a call to a function in Dafny code, the body of the function is available for reasoning about the effect of the function. But for recursive functions, it generally only does this once or twice, as that is usually sufficient to form an inductive proof. And always unrolling multiple times can reduce performance.
You can request that Dafny unroll a function multiple times by using the {:fuel}
attribute.
The value of the attribute is the number of times the function will be unrolled. This is still a fixed upper limit,
but it does the trick in this case:
function {:fuel 10} Sum(s: seq<nat>): nat {
if |s| == 0 then 0
else s[0] + Sum(s[1..])
}
lemma Sum1(s: seq<nat>)
requires |s| == 1
ensures Sum(s) == s[0]
{
// trivial
}
lemma Sum2(s: seq<nat>)
requires |s| == 2
ensures Sum(s) == s[0] + s[1]
{
// Doesn't work. I need...
// Sum1(s[1..]);
}
lemma Sum3(s: seq<nat>)
requires |s| == 3
ensures Sum(s) == s[0] + s[1] + s[2]
{
// Doesn't work. I need...
// Sum2(s[1..]);
}
A function will also keep unrolling if it has an argument that is a literal and that argument decreases
on each recursive call. So for this example we can write a helper function that takes a nat
argument
and give it a literal value that tells it how much to unroll.
function Sum(s: seq<nat>): nat {
if |s| == 0 then 0
else s[0] + Sum(s[1..])
}
function Sum_(s: seq<nat>, n: nat): nat
ensures Sum(s) == Sum_(s,n)
ensures |s| > 0 && n > 0 ==> Sum_(s,n) == s[0] + Sum_(s[1..], n-1)
{
if |s| == 0 || n == 0 then Sum(s)
else s[0] + Sum_(s[1..], n-1)
}
lemma Sum1(s: seq<nat>)
requires |s| == 1
ensures Sum(s) == s[0]
{
// trivial
}
lemma Sum3(s: seq<nat>)
requires |s| == 3
ensures Sum(s) == s[0] + s[1] + s[2]
{
var _ := Sum_(s, 3);
}
lemma Sum9(s: seq<nat>)
requires |s| == 9
ensures Sum(s) == s[0] + s[1] + s[2] + s[3] + s[4] + s[5] + s[6] + s[7] + s[8]
{
var _ := Sum_(s, 9);
}
With this solution, the number of unrollings can be set at the call site, rather than in the function definition.
This paper gives some technical insight into how recursive functions are handled in situations like these examples.
Why do nested modules not see the imports of their enclosing modules?
Question
Why is my import opened statement not working in the following example:
module A {
type D = string
}
module Y {
import opened A
module X {
type X = D
}
module Z {
type Z = D
}
}
Answer
Although nested modules are nested inside other modules, they should really be thought of as their own module.
There is no particular benefit to module A.B
from being nested inside module A
none of the declarations of A
are visible in B
other than the names of sibling modules of B
.
The benefit is to module A
, for which the nested module B
is a namespace that can group some related declarations together.
Accordingly, if you want some names from another module to be available within a submodule, you must import that directly in the submodule. The example above becomes this:
module A {
type D = string
}
module Y {
module X {
import opened A
type X = D
}
module Z {
import opened A
type Z = D
}
}
Is there a way to test that two types are the same?
Question
Is there a way to test that two types are the same, as in this exmple:
abstract module Mixin1 { type T = int }
abstract module Mixin2 { type T = int }
abstract module Mixins1and2 {
import M1 : Mixin1
import M2 : Mixin2
lemma typeConstraint() ensures M1.T == M2.T
}
Answer
No. Types are not first-class entities in Dafny. There are no variables or literals of a type TYPE
.
There is a type test for reference types, namely is
, but that is not a strict type equality but a
test that the dynamic type of a reference object is the same as or derived from some named type.
When a lemma has multiple ensures clauses, I’m finding that they interact, when I expected them to be independent. For example, commenting out one of them can make another one not verify. How should I think about this?
Question
When a lemma has multiple ensures clauses, I’m finding that they interact, when I expected them to be independent. For example, commenting out one of them can make another one not verify. How should I think about this?
Answer
Multiple ensures clauses, such as ensures P ensures Q ensures R
is equivalent to the conjunction, in order, of the ensures predicates: ensures P && Q && R
.
The order is important if an earlier predicate is needed to be sure that a later one is well defined. For example,
if a
is an array?
, the two predicates in ensures a != null ensures a.Length > 0
must be in that order because a.Length
is well-defined only if a != null
.
In addition, sometimes one ensures clause serves as an intermediate reasoning step for the next one. Without the earlier clause, Dafny can have trouble proving the second one, even though it is valid. With the first predicate as an intermediate step, the second is then more easily proved.
This order dependence of postconditions is also the case for preconditions and loop invariants
What is the difference between a lemma and a ghost method?
Question
What is the difference between a lemma and a ghost method?
Answer
A lemma
is a ghost method
that does not have a modifies
clause. Lemmas also do not typically return results.
However, in most places where a lemma is used, it must be declared as a lemma. For example the lemma call that can be part of an expression must call a method that is declared to be a lemma, not a ghost method.
A lemma may also be called as a statement in the body of a method, but here a ghost method is allowed as well, so either can be used.
In an invariant, I want to say that once a boolean variable that starts false is set to true, it remains true forever. Can I use old for this?
Question
In an invariant, I want to say that once a boolean variable that starts false is set to true, it remains true forever. Can I use old for this?
Answer
Almost but not quite. old
gives you the value of an expression in the method’s pre-state or at given label.
Equivalently. you can stash the value of an expression at some point in the control flow in some temporary (even ghost) variable.
Then you can state a predicate saying “if the expression was true at that specific point, then it is still true now when I am testing it”.
But that is not quite saying “once an expression becomes true, it stays true”. For that you need a more complicated solution:
- declare a ghost variable
nowTrue
, initialized tofalse
- at every location where the expression (call it
e
) is set,- first test its new value:
if nowTrue && !e { FAILURE }
- and then set the ghost value
nowTrue := nowTrue || e;
- first test its new value:
When proving an iff (<==>), is there a nice way to prove this by proving each side of the implication separately without making 2 different lemmas?
Question
When proving an iff (<==>), is there a nice way to prove this by proving each side of the implication separately without making 2 different lemmas?
Answer
Here are two ways to prove A <==> B
:
if A {
// prove B...
}
if B {
// prove A...
}
Another way is
calc {
A;
==
// ...
==
B;
}
Is there a way to do partial application for functions?
Question
Is there a way to do partial application for functions in Dafny?
Answer
Given
function f(i: int, j: int): int {...}
one can create a new partially-evaluated function, say evaluating the first argument at 2
, by writing the lambda expression k => f(2,k)
.
But note that this does not do any evaluation, partial or not. It merely defines a new function f'
of one argument, such at f'(k)
is f(2,k)
.
Dafny does not permit the syntax f(2)
as a shorthand for k => f(2,k)
.
Why can a ghost const not be used as a witness? Does the compiler need to use the witness as an initial value?
Question
Why can a ghost const not be used as a witness? Does the compiler need to use the witness as an initial value?
Answer
A type can be
- auto-initializing (which means the compiler knows of a value of the type)
- nonempty (which means there is a value of the type, but the compiler might not know it)
- possibly empty (neither or the above is true)
To show a type is auto-initializing, you may need to provide a witness clause. The expression given in the witness clause must be compilable.
To just show a type is nonempty, you can use a ghost witness clause. It takes a ghost expression, so you should be able to use your ghost const here.
If you don’t care about either, you can say witness *
, which makes the type be treated as possibly empty.
When declaring generic types, one can use type characteristics to indicate any restrictions on the types that may be substituted for a type parameter.
For example, writing class A<T(0)>
says that types substituted fo T
must be auto-initializing;
writing class A<T(00)>
says that such types must be non-empty.
How do I use forall
statements and expressions in a lemma?
Question
If I’m trying to prove a lemma in Dafny with a forall
statement that needs help in the body ({}
) of the lemma, how do I make an arbitrary variable in the body of the lemma to help prove the forall
statement?
Answer
Note that there is a difference between a forall
expression, which is a universally quantified formula, and a forall
statement, which is used to establish the truth of a universally quantified formula. To do what you want to do, write:
lemma MyLemma()
ensures forall s :: P(s) ==> Q(s)
{
forall t | P(t)
ensures Q(t)
{
// Here, t is in scope, and P(t) is assumed.
// Your task here is to prove Q(t) for this particular t.
}
// Here, you get to assume "forall t :: P(t) ==> Q(t)"
}
The forall
in the ensures is an expression and the forall
in the body of the lemma is a statement.
This use of the forall
statement is what logicians call “universal introduction”.
Note the slight difference in syntax between the forall
expression and forall
statement.
Although Dafny tries to make the syntax of these sorts of things as similar as possible between expressions and statements, there are some differences.
The following Dafny Power User note may be helpful in understanding the syntax: Dafny Power User: Statement vs. Expression Syntax.
Is there any difference between a method without a modifies clause and a function with a reads this clause? I know that the latter you can use in expressions, but otherwise, is there anything the former can do that the latter can’t, for example?
Question
Is there any difference between a method without a modifies
clause and a function method with a reads this
clause? I know that the latter you can use in expressions. Is there anything the former can do that the latter can’t, for example?
Answer
Compared to a function, a method can
- allocate objects and arrays (
new
) - use non-determinism
- use loops
- have multiple outputs
- read anything in the heap
Dafny doesn’t like when a type and a module have the same name. How can I fix this?
Question
Dafny doesn’t like when a type and a module have the same name. How can I fix this?
module Result {
datatype Result<T> = Success(x: T) | Failure(e: string)
}
module Test {
import opened Result
function method f(): Result<int>
{
Success(0)
}
}
produces
FAQNameConflict.dfy(6,23): Error: Wrong number of type arguments (1 instead of 0) passed to module: Result
1 resolution/type errors detected in FAQNameConflict.dfy
Answer
The problem is that in the Test
module, the name Result
is both a module name and a datatype name.
The module name takes precedence and so the resolution error happens.
(Despite the error message, modules never have type arguments.)
This situation can be fixed two ways. First, write Result.Result
to mean the datatype. Or second,
import the module with a new name, such as import opened R = Result
. Then inside module Test, there is
the name R
for a module and the name Result
for the datatype. The following code shows both these options.
module Result {
datatype Result<T> = Success(x: T) | Failure(e: string)
}
module Test {
import opened Result
function method f(): Result.Result<int>
{
Success(0)
}
}
module Test1 {
import opened R = Result
function method f(): Result<int>
{
Success(0)
}
}
“Is there a way to prevent ‘Warning: note, this forall statement has no body’ from occurring? I have a forall loop with no body that results in the lemma verifying, but if I add a body (even an empty body) the lemma doesn’t verify.”
Question
Is there a way to prevent “Warning: note, this forall statement has no body” from occurring? I have a forall loop with no body that results in the lemma verifying, but if I add a body (even an empty body) the lemma doesn’t verify.
Answer
The Dafny verifier allows you to omit the body of various constructs. For example, if you write a method without a body, the verifier will gladly check calls to the method against that specification (after checking the well-formedness of the method specification). This is nice, because it lets you write the specification of a method and then start using it in other places, only to later return to filling in the body of the method.
The verifier is happy with such a body-less thing, but the once verification is done and you’re asking Dafny to compile your program, the compiler will complain, because it doesn’t know how to synthesize code for the method specification you wrote.
You can also do this with loops. For example, you can write
while i < N
invariant s == i * (i + 1) / 2
and not give a body. Again, the verifier is happy and will gladly check the rest of the code that follows the loop. This allows you to write down the loop invariant and make sure that the code after the loop is fine, only to later return to filling in the loop body.
If you leave off the body of a loop, Dafny will gently remind you of this by giving a warning like “this loop statement has no body”.
The forall statement is an aggregate statement. It simultaneously performs something for all values of the bound variables. In proofs, the forall statement is used as the counterpart of what logicians call “universal introduction”. In code, the forall statement has various restrictions, and is typically used to initialize all elements of an array. The forall statement can also be declared without a body. Again, the verifier is happy to reason about its use, but the compiler would complain that there’s no body.
So, in the end, you do need to prove a body for your forall statements. You’ll have to make sure the body establishes the postcondition of the forall statement.
And even for functions and lemmas without bodies, even though the verify does not complain, they are unproved assumptions in your program.
Is there a way to disable termination checks for recursive predicate definitions that I know to be logically consistent?
Question
Is there a way to disable termination checks for recursive predicate definitions that I know to be logically consistent?
Answer
Well, first of all, be careful about thinking things like “I know this to be logically consistent”. Verifiers exist to check our human tendency to hand-wave over questionable assumptions.
That said, you can do something like this:
predicate P(x: int, terminationFiction: int)
decreases terminationFiction
{
assume 0 < terminationFiction;
P(x, terminationFiction - 1)
}
That may cause some quantification triggering problems and may need an axiom like
forall x,j,k:int :: P(x, j) == P(x, k)
It can also help to manually instantiate an axiom to avoid triggering issues: declare the axiom like this:
lemma {:axiom} PSynonym(x: int, j: int, k: int)
ensures P(x, j) == P(x, k)
and then call the lemma as needed.
Is there a way to specify that all fields of an object, except a given one, don’t change?
Question
Is there a way to specify that all fields of an object, except a given one, don’t change?
Answer
Instead of writing modifies this
or modifies o
, you can write modifies this`f
(equivalently modifies `f
)
or modifies o`f
to indicate that just the field f
of this
or o
, respectively, may be assigned to.
How do labels in preconditions work?
Question
How do labels in preconditions work?
Answer
method M0(x: int)
requires x == 0
{
assert x < 10; // verifies
}
method M1(x: int)
requires Zero: x == 0
{
// the following assertion does not verify, because labeled
// preconditions are hidden
assert x < 10; // error
}
method M2(x: int)
requires Zero: x == 0
{
// by revealing the hidden precondition, the assertion verifies
reveal Zero;
assert x < 10; // verifies
}
In the code example above, the precondition x == 0
is labeled with Zero
.
Unlabeled preconditions are assumed at the beginning of a method body,
but labeled preconditions are not. Labeled preconditions are only assumed
when they are explicitly reveal
ed. So in the example, the assert in method
M1
cannot be proved because the fact x < 10
is not known.
In method M2
, that fact is made known by the reveal
statement, and so here
the assert
can be proved. The effect of the reveal
is just as if an assumption were
made at the point of the reveal
statement.
Note that if the reveal
statement is in a by
block of an assert by
statement, then the revealing is limited to the proof of the
corresponding assert
.
These same rules apply to labeled assert
statements.
There is an expanded discussion in section 7 of Different Styles of Proofs.
Where are attributes documented?
Question
Where are attributes documented? Why does my attribute not seem to make a difference?
Answer
In general, attributes are documented in a chapter of the reference manual; some are also documented in the sections in which the language feature for which they are relevant is described. However, at present not all of them are documented.
Some projects with forks of Dafny may introduce attributes of their own. Keep in mind, that any attributes not recognized by Dafny are silently ignored, to allow for such extension.
Is there a way to ask Dafny to die on its first verification failure?
Question
Is there a way to ask Dafny to die on its first verification failure?
Answer
No. At least as of version 3.7.3.
I can define a trait with some type parameters say trait Test<A, B, C>. When I use this trait is there a way to get Dafny to infer these types for me?
Question
I can define a trait with some type parameters say trait Test<A, B, C>
. When I use this trait is there a way to get Dafny to infer these types for me?
Answer
Type inference, though quite extensive in its effect, only works within the bodies of functions and methods. Types in signatures and actual values for type parameters need to be written explicitly.
When type inference is used (within a body), types are determined by how they are used, not just be initializing expressions. So the inferred type in a declaration may depend on code that appears textually after the declaration. Here is some example code:
class C<X(0)> {
static method M() returns (x: X) {
}
method P() {
var x0 := M(); // type of x0 inferred to be X, from M()'s signature
var x1 := C<int>.M(); // type of x1 inferred to be int
var x2: int := C.M(); // M() instantiated with int
var x3 := C.M(); // error: type of x3 is underspecified
var x4: int := M(); // error: M() instantiated with X, but x4 has type int
}
}
Does Dafny have monadic error handling?
Question
Does Dafny have monadic error handling?
Answer
Yes.
In particular, see the section of the reference manual on Update with Failure statements. The (draft) standard library includes some types needed for error handling.
You can define your own monadic error type by following examples in the RM and the draft library. A simple case is
datatype Outcome<T> =
| Success(value: T)
| Failure(error: string)
{
predicate IsFailure() {
this.Failure?
}
function PropagateFailure<U>(): Outcome<U>
requires IsFailure()
{
Failure(this.error) // this is Outcome<U>.Failure(...)
}
function Extract(): T
requires !IsFailure()
{
this.value
}
}
What is the :-
operator? How does it work?
Question
What is the :-
operator? How does it work?
Answer
This operator is called the elephant operator (because it has a trunk). It is used to write code that exits on failure (much like exceptions in other programming languages or the ? operator in Rust). The topic is discussed at length in the section of the reference manual on Update with Failure statements.
In brief, Dafny permits methods to return values of failure-compatible types. If the result of a method is being assigned to a variable with the :-
operator and the result is a failure, then the method exits immediately, with the failure being propagated to the calling method.
What is the :-
operator? How does it work?
Question
What is the :-
operator? How does it work?
Answer
This operator is called the elephant operator (because it has a trunk). It is used to write code that exits on failure (much like exceptions in other programming languages or the ? operator in Rust). The topic is discussed at length in the section of the reference manual on Update with Failure statements.
In brief, Dafny permits methods to return values of failure-compatible types. If the result of a method is being assigned to a variable with the :-
operator and the result is a failure, then the method exits immediately, with the failure being propagated to the calling method.
What is the meaning of and differences among ->
, -->
, ~>
?
Question
What is the meaning of and differences among ->
, -->
, ~>
?
Answer
These are all used in designating the type of functions; they are sometimes called arrow types.
In each case, A -> B
is the type of a function taking an argument of type A
and producing a value of type B
;
The function argument types can be enclosed in parentheses, and if the number of arguments is not 1 or the argument is a tuple type, then the argument types must be enclosed in parentheses. For example,
(A, B) -> C
is a type of function that takes two arguments; ((A, B)) -> C
takes as argument a 2-tuple.
The three symbols in the question denote different sorts of types of functions:
->
denotes a total function that is independent of the heap; it may not have arequires
clause (precondition) or areads
clause-->
denotes a partial function; it may have a precondition, but may not have areads
clause, and so it also is independent of the heap~>
denotes a partial and possibly heap-dependent function; it may haverequires
andreads
clauses
If a function is independent of the heap, it is useful to say so, either in its declaration or the type that describes it. The value returned by a heap-independent function depends only on its arguments and not on the program state;
thus it is easier to reason about its properties. Working with heap-dependent functions is much more difficult than with heap-independent functions, so use ->
or -->
if you can. And note that Dafny does not support polymorphic arrow types.
What is the difference between function
, method
, function method
, and function by method
?
Question
What is the difference between function
, method
, function method
, and function by method
?
Answer
The names of these alternatives will be changing between Dafny 3 and Dafny 4:
function
(function method
in Dafny 3) – is a non-ghost functionghost function
(function
in Dafny 3) – is a ghost function- function by method is a ghost function with an alternate compilable (non-ghost) method body (cf. the reference manual section on function declarations)
method
declares a non-ghost methodghost method
declares a ghost method, though this is almost always done using alemma
instead
Note that
- Methods may have side effects but may not be used in expressions.
- Functions may be used in expressions but may not have side effects.
- Methods do not have reads clauses; functions typically do.
- Non-ghost methods and non-ghost functions may not be used in ghost code.
Is it possible to restrict a type parameter to be a reference type? I see you can use T(!new) but I’m looking for the opposite.
Question
Is it possible to restrict a type parameter to be a reference type? I see you can use T(!new)
but I’m looking for the opposite.
Answer
No. The only restrictions available (as of version 3.7.3) are
T(==)
- type supports equalityT(0)
- type is auto-initializableT(00)
- type is non-emptyT(!new)
- type may not be a reference type or contain a reference type
See the appropriate section of the reference manual for more information.
A seq
is an object reference, right?
Question
A seq
is an object reference, right?
Answer
No. Types in Dafny are either heap-dependent (reference) types or strict value-types. Built-in types are typically value types. Value types are heap independent, though they may be stored in the heap as part of an object.
Value types include bool
, int
, char
, real
, ORDINAL
, datatypes and co-datatypes, arrow types, bit-vector types, seq
, set
, iset
, multiset
, map
, imap
, string
, tuple types, and subset or newtypes with value type bases.
Reference types are classes, traits, arrays, and iterators.
The values of value types are immutable; new values may be computed but are not modified. Integers are a good mental model for value types, but in Dafny, datatypes, sequences, sets, and maps are also immutable values. Note that though the values of these types are immutable, they may contain instances of reference types (which might be mutable).
How do I pattern match against a head and tail of a sequence or against a set?
Question
How do I pattern match against a head and tail of a sequence or against a set?
Answer
You can’t. Match expressions and statements operate on datatype
values and not on other Dafny types like sets, sequences, and maps. If statements, perhaps with binding guards, may be an alternative.
How do I create a new empty map (or set or sequence)?
Question
How do I create a new empty map (or set or sequence)?
Answer
An empty sequence is denoted by []
, an empty set by {}
, an empty multiset by multiset{}
, and an empty map by
map[]
. The type of the empty collection is typically inferred from its subsequent use.
The various operations on values of these types are described in the reference manual section on Collection Types.
I have a module that exports a bunch of things. In another module I only need to use 1 thing. Is there a way to import only the thing that I want?
Question
I have a module that exports a bunch of things. In another module I only need to use 1 thing. Is there a way to import only the thing that I want?
Answer
The short answer is: use an export set.
Here is an example. Suppose you have this code:
module A {
export JustJ reveals j
const i: int := 64
const j: int := 128
}
module B {
//import opened A // imports both i and j
import opened A`JustJ // just imports j
}
The export
directive in module A
just exports the name j
in the export set JustJ
.
So then you can import just j
in B
by importing A`JustJ
.
You can create as many export sets as you like, for different contexts. See the details here.
This feature does put the onus of defining the groups of exportable names on the supplying module.
Your question asks for such control by the receiving module. The best course for the receiving
module is to not use import opened
and just use a qualified name for the one thing that is being used from the
supplying module.
What is the difference between modifies this, modifies this.x, and modifies this`x?
Question
What is the difference between modifies this
, modifies this.x
, and modifies this`x
?
Answer
A modifies
clause for a method lists object references whose fields may be modified by the body of the method.
this
means that all the fields of thethis
object may be modified by the bodythis.x
(wherex
is a field ofthis
and has some reference type) means that fields ofx
may be modified (but not the fieldx
itself ofthis
)this`x
means that just the fieldx
ofthis
may be modified (and not any other fields, unless they are listed themselves)
If there are multiple items listed in the modifies clause, the implicit clause is the union of all of them.
More on framing (modifies
and reads
clauses) can be found in the reference manual section on Framing specifications.
How does one define a record?
Question
How does one define a record?
Answer
The Dafny datatype
feature lets you define simple or complex records, including recursive ones.
A simple enumeration record might be defined as
datatype ABCD = A | B | C | D
Variables of type ABCD
can take one of the four given values.
A record might also be a single alternative but with data values:
datatype Date = Date(year: int, month: int, day: int)
where a record instance can be created like var d := Date(2022, 8, 23)
and componenents retrieved like d.year
.
There can be multiple record alternatives each holding different data:
datatype ABCD = A(i: int) | B(s: string) | C(r: real) | D
const a: ABCD := A(7)
const b: ABCD := B("asd")
const c: ABCD := C(0.0)
const d: ABCD := D
You can determine which alternative a record value is with the built-in test functions: with the definitions above, a.A?
is true and b.C?
is false. And you can extract the record alternative’s
data: in the above a.i
is well-defined if a.A?
is true, in which case it has the value 7
.
There is more description of datatypes here.
“What does forall v :: v in vals ==> false
evaluate to if vals
is non-empty?”
Question
What does forall v :: v in vals ==> false
evaluate to if vals
is non-empty?
Should it be false? I’m having some problem proving the last assertion in Dafny.
assert vals != [];
assert MatchingResult() == (forall v :: v in vals ==> false);
assert !MatchingResult();
Answer
The problem here is the trigger on the quantification expression.
Dafny sees the forall
quantifier but uses it only when there is a v in vals
fact in the context for some v (this is what the annotation on the forall in the VSCode IDE means: Selected triggers: {v in vals}). So until you give it a concrete fact to “trigger” on, it doesn’t use your quantifier.
It is not recommended that users insert triggers in their Dafny code. Rather, it is better to reorganize the quantification expressions to make the desired trigger more obvious to the Dafny tool. Here are two references that explain triggers in more detail:
“Why does Dafny complain about this use of a set constructor: set i: int | Contains(i)
?”
Question
Why does Dafny complain about this use of a set constructor: set i: int | Contains(i)
?
Here is an example:
module test {
ghost const things: set<int>
predicate Contains(t: int)
{
t in things
}
function ThisIsOk(): set<int> {
set i: int | i in things && i > 0
}
function ThisIsNotOk(): set<int> {
set i: int | Contains(i) && i > 0
}
}
which produces the error “the result of a set comprehension must be finite, but Dafny’s heuristics can’t figure out how to produce a bounded set of values for ‘i’”.
Answer
In constructing a set
, which must be finite, Dafny must prove that the set is indeed finite.
When the constructor has i in things
inlined, Dafny can see that the set of values of i
for which the predicate is true can be no larger than things
, which is already known by declaration to be
a finite set. However, when the predicate is Contains
, Dafny cannot in general see that fact.
The Dafny’s heuristic for determining that the constructor is producing a finite set does not
inspect the body of Contains
even though that is a transparent function. Note that if the constructor and the return type of ThisIsNotOK
is made iset
, Dafny does not complain.
An alternate general way to refine a set is given by this example:
module test {
ghost const things: set<int>
function RefineThings(condition: int -> bool): set<int>
{
set t: int | t in things && condition(t)
}
function ThisIsOk(): set<int> {
set i: int | i in things && i > 0
}
function ThisIsOkAgain(): set<int> {
RefineThings(i => i > 0)
}
}
What’s the syntax for paths in include directives? How do they get resolved?
Question
What’s the syntax for paths in include directives? How do they get resolved?
Answer
An include directive is the include
keyword followed by a string literal (in quotes).
The string is a conventional file path for the OS on which you are running and is the full file name with extension.
The filepath can be either absolute or relative; if relative, it is relative to the current working directory
(i.e., the result of pwd
on Linux).
As of version 3.7.3, there is no “include path” that might allow paths relative to other locations, but it is a feature request.
How do {:split_here}
and {:focus}
work to divide up a proof?
Question
How do {:split_here}
and {:focus}
work to divide up a proof?
Answer
Verifying a method requires proving a large number of assertions. Dafny uses a backend prover (an SMT solver) to verify assertions. The prover may become better or worse at verifying an assertion if you ask it to also verify another assertion. Dafny allows you to split up a group of assertions into batches, where each batch is sent to the SMT solver separately, so the verification of each batch is not influenced by the others.
One default way of operating is to combine all assertions into one batch, leading to a single run of the prover. However, even when this is more efficient than the combination of proving each assertion by itself (with prover start-up costs and the like for each one), it can also take quite a while to give a final result, possibly even timing-out.
So sometimes it is preferable to prove each assertion by itself, using the -vcsSplitOnEveryAssert
command-line option.
But there are also intermediate options. Look at the various command-line options under “Verification-condition splitting”.
Another way to split up the way in which assertions are grouped for proof is to use the two attributes {:focus}
and {:split_here}
,
both of which are applied to assert statements.
In brief, {:focus}
says to focus on the block in which the attribute appears. Everything in that block is one assertion batch and everything
outside that block is another assertion batch. It does not matter where in the block the {:focus}
attribute appears. If there are multiple
{:focus}
attributes, each block containing one (or more) is one assertion batch, and everything outside of blocks containing {:focus}
attributes
is a final assertion batch. This attibute is usually used to break out if-alternatives or loop-bodies into separate verification attempts.
{:split_here}
creates an assertion batch of all assertions strictly before the attributed statement and another of the assertions at or after
the attributed statement. This attribute is usually used to break up long stretches of straight-line code.
Some examples that show how this works for multiple nested blocks are given in the reference manual, here and here.
How does one declare a type to have a “default” initial value, say a type tagged with {:extern}?
Question
How does one declare a type to have a “default” initial value, say a type tagged with {:extern}?
Answer
There is no general way to do this. Subset types and newtypes have witness clauses and types that are auto-initializable have a default, but those rules do not apply to anonymous extern types. Particularly for abstract types, there is not even a way to infer such a value.
You can manually initialize like this:
type {:extern} TT {
}
function {:extern} init(): TT
method mmm() {
var x: TT := init();
var y:= x;
}
A module A has names from an import opened
of another module B, but if C imports A, it does not get those names. Please explain.
Question
A module A has names from an import opened
or another module B, but if C imports A, it does not get those names. Please explain.
Answer
Here is some example code:
module A {
const a: int := 0
}
module B {
import opened A
const b: int := a; // This is A.a, known as a here because of the import opened
}
module C {
import opened B
const c: int := b; // This is B.b because of the import opened
const d: int := A.a; // B.A is known as A because of the import opened in B
const e: int := a; // ILLEGAL - opened is not transitive
}
The import opened
directive brings into the importing module all the names declared in the imported module,
including the names of modules from import statements in the importee, but not names introduced into the importee (here B
) by an import opened directive. opened
is not transitive. As shown in the example code, the names in A
are still available in C
by qualifying them.
Are there functional alternatives to recursive calls that are more efficient or use less stack space?
Question
Are there functional alternatives to recursive calls that are more efficient or use less stack space?
Answer
One way to reduce the number of recursive calls is to use Dafny’s function-by-method construct to give a better performing implementation. For example
function Fib(n: nat): nat {
if n < 2 then n else Fib(n-1) + Fib(n-2)
}
it a very natural but quite inefficient implementation of the Fibonacci function (it takes Fib(n)
calls of Fib
to compute Fib(n)
, though only to a stack depth of n
).
With function-by-method we can still use the natural recursive expression as the definition but provide a better performing implementation:
function Fib(n: nat): nat
{
if n < 2 then n else Fib(n-1) + Fib(n-2)
} by method {
var x := 0;
var y := 1;
for i := 0 to n
invariant x == Fib(i) && y == Fib(i+1)
{
x, y := y, x+y;
}
return x;
}
This implementation both combines the two computations of Fib and also, more importantly, turns a tail recursive recursion into a loop.
How do I read a file as a string?
Question
How do I read a file as a string?
Answer
You can’t in pure Dafny. Not yet. Such a capability will eventually be part of a standard IO library.
What you can do is to write such a function in another language, say Java, and then use it in Dafny by extern declarations.
Can I ask Dafny to not check termination of a function?
Question
Can I ask dafny to not check termination of a function?
Answer
Functions must always terminate, and it must be proved that they terminate.
Methods on the other hand should also terminate , but you can request the the proof be skipped using decreases *
, as in
method inf(i: int)
decreases *
{
inf(i);
}
Eventually you should put an actual termination metric in place of the *
and prove termination.
The reference manual has more information about termination metrics in the section on decreases
clauses.
What does {:termination false} do on trait? It looks like it is required if I want to extend traits from other modules.
Question
What does {:termination false}
do on trait? It looks like it is required if I want to extend traits from other modules.
Answer
The attribute turns off termination checking for the trait. Here is an example
module foo1 {
trait {:termination false} Foo {
method bar()
}
class Baz{
static method boz(foo: Foo){ foo.bar(); }
}
}
module foo2 {
import opened foo1
class Boz extends Foo {
method bar(){
Baz.boz(this);
}
}
}
In this example, omitting {:termination false}
provokes the error “class ‘Boz’ is in a different module than trait ‘foo1.Foo’. A class may only extend a trait in the same module, unless the parent trait is annotated with {:termination false}.”.
The {:termination false}
is only needed when there is dynamic dispatch across module boundaries.
It does put the onus on the user to prove termiation, as Dafny is no longer doing so.
The origin of this situation has to do with the interaction of current decreases clauses and traits.
Dafny decreases clauses were designed before the language had dynamic dispatch via trait members. As such, decreases clauses are made to be as simple as possible within each module, and decreases clauses are unnecessary across modules. When dynamic dispatch was added to the language, a draconian restriction was put in place to maintain soundness, namely to disallow dynamic dispatch across module boundaries. This is enforced by insisting that a class that implements a trait is declared in the same module that declares the trait.
The draconian restriction outlaws the useful case where a trait is placed in a library. Indeed, we are seeing this in dafny-lang/libraries
now. So, Dafny supports a way for users to lift the draconian restriction and instead take responsibility themselves for termination of dynamically dispatched calls via a trait–it is to mark the trait with {:termination false}
.
The status of solutions to this problem are discussed here.
How do I make Dafny termination checking happy with mutual recursion?
Question
How do I make Dafny termination checking happy with mutual recursion, like the following example:
datatype T = Y | N | B(T,T)
function f(x : T) : bool {
match x {
case Y => true
case N => false
case B(x,y) => g(x,y)
}
}
function g(x : T, y : T) : bool {
f(x) && f(y)
}
If g
is inlined there is no problem. What should I do?
Answer
Termination of recursion is proved using a decreases
clause. For the single function
Dafny can successfully guess a decreases metric. But for this mutual recursion case,
the user must supply on.
The termination metric for a recursive datatype (like T
here) is the height of the tree denoted by the argument x
, in this case.
So there is definitely a decrease in the metric from the call of f
to the call of g
, but there is not when g
calls f
.
One solution to this situation is the following:
datatype T = Y | N | B(T,T)
function f(x : T) : bool
decreases x, 1
{
match x {
case Y => true
case N => false
case B(x,y) => g(x,y)
}
}
function g(x : T, y : T) : bool
decreases B(x,y), 0
{
f(x) && f(y)
}
Here when f
calls g
, the metric goes from x, 1
to B(x.x, x.y), 0
. Because x
is the same as B(x.x, x.y)
, the lexicographic ordering looks
at the next component, which does decrease from 1
to 0
. Then in each case that g
calls f
, the metric goes from B(x,y), 0
to x,1
or y,1
,
which decreases on the first component.
Another solution, which is a pattern applicable in other circumstances as well, is to use a ghost parameter as follows:
datatype T = Y | N | B(T,T)
function f(x : T) : bool
decreases x, 1
{
match x {
case Y => true
case N => false
case B(x',y') => g(x,x',y')
}
}
function g(ghost parent: T, x : T, y : T) : bool
decreases parent, 0
requires x < parent && y < parent
{
f(x) && f(y)
}
More on the topic of termination metrics can be found here.
Can it be proved that a class instance is not an instance of a trait?
Question
Can it be proved that a class instance is not an instance of a trait, as in the following example?
trait A<T> {}
class B {}
lemma Foo(v: object)
ensures v is B ==> !(v is A<object>)
{}
Answer
No. Although the lemma is valid and may be stated as an axiom, Dafny does not internally model the type hierarchy and so does not have the information to prove that statement. Such an axiom would have to be manually checked against the type hierarchy if the definitions of the types involved were to change.
Is there a nice way to turn a set
into a seq
?
Question
Is there a nice way to turn a set into a seq?
Answer
There is as yet no built-in simple function but there are various idioms that can accomplish this task.
Within a method (where you can use a while loop), try var acc: seq<int> := [];
while s != {} { var x: int :| x in s; acc := acc + [x]; s := s - {x}; }
You could use a function-by-method to encapsulate the above in a function.
Here is an extended example taken from Dafny Power User: Iterating over a Collection.
function SetToSequence<A(!new)>(s: set<A>, R: (A, A) -> bool): seq<A>
requires IsTotalOrder(R)
ensures var q := SetToSequence(s, R);
forall i :: 0 <= i < |q| ==> q[i] in s
{
if s == {} then [] else
ThereIsAMinimum(s, R);
var x :| x in s && forall y :: y in s ==> R(x, y);
[x] + SetToSequence(s - {x}, R)
}
lemma ThereIsAMinimum<A(!new)>(s: set<A>, R: (A, A) -> bool)
requires s != {} && IsTotalOrder(R)
ensures exists x :: x in s && forall y :: y in s ==> R(x, y)
How do I declare a default value for a parameter of a method or function?
Question
How do I declare a default value for a parameter of a method or function?
Answer
The parameters of methods and functions can be referred to by name.
method m( i: int, j: int, k: int) {}
method q() {
m(4, k:= 7, j:=8);
}
In the left-to-right sequence of actual arguments, once a parameter is referred to by name, all the rest must also be referred to by name. The named arguments may be in any order.
Furthermore, arguments can be given default values.
method m( i: int, j: int, k: int := 0) {}
method q() {
m(4, 4, k:=8);
m(1, j:=2);
m(1,2);
}
In the left-to-right sequence of actual arguments, once a parameter is given a default value, all the rest must also have a default value. Arguments may still be referred to by name, but now any named argument with a default is optional. If there are no names at all, then it is always the last arguments that are omitted if the actual argument list is shorter than the formal parameter list, and they must all have defaults.
Finally, a parameter may be declared as nameonly
, in which case it must be referred to by name.
method m( i: int, j: int, nameonly k: int := 0, q: int := 8) {}
method q() {
// m(4, 4, 8 ); // Error
m(4, 4, q:=9);
m(4, 4, k:=8);
}
Such a parameter may but does not need to have default value, but if it does not, it cannot be omitted.
I just realized that a function I was compiling had a type error inside a match case. Instead of giving a compile error I was getting a redundant clause warning for the second case. What is the reason for this?
Question
I just realized that a function I was compiling had a type-error inside a match case. Instead of giving a compile error I was getting a redundant clause warning for the second case. What is the reason for this?
Answer
Here is a situation that can cause this error:
datatype AB = A | B
method test(q: AB) {
var c := match q { case a => true case b => false };
}
The example has an error on the second case
saying this branch is redundant.
The problem here is that both a
and b
are undeclared variables. Consequently they both match
in match expression q
no matter what q
’s value is. Because a
matches no matter what,
the second case is redundant.
What is usually intended by such code is something like this:
datatype AB = A | B
method test(q: AB) {
var c := match q { case A => true case B => false };
}
which causes no type errors.
The observation here is that misspelled type names in case patterns can cause silent unexpected behavior. It is likely that a lint warning will be produced for the above anti-pattern in some future version of Dafny.
Is there a way I can pass a variable with a generic type to a method with a concrete type?
Question
Is there a way I can pass a variable with a generic type to a method with a concrete type? Here is some motivating code:
predicate Goo<K, V>(m: map<K, V>)
requires m.keyType is string // Can I do something like this?
{ Foo(m) }
predicate Foo<V>(m: map<string, V>)
Answer
In short, no.
There are a few problems here. First there is no way to extract the type of the keys of a map as a type value. Dafny does not have the capability to reason about
types as first-class entities. In fact the is
operator takes a value and a type, not two types.
We could try writing the precondition as requires m.Keys is set<string>
, but that is not permitted either as m.Keys
is a set<K>
and is not comparable to set<string>
with is
.
How can ghost code call methods with side effects?
Question
How can ghost code call methods with side effects?
Answer
Ghost code may not have any effect on non-ghost state, but ghost code can have effects on ghost state. So a ghost method may modify ghost fields, as long as the specifications list the appropriate fields in the appropriate modifies clauses. The example code below demonstrates this:
class C {
ghost var c: int
ghost method m(k: int)
modifies this
ensures c == k
{
c := k;
}
ghost method p() {
var cc := new C;
cc.m(8);
assert cc.c == 8;
}
}
How do I create and use an iterator?
Question
How do I create and use an iterator?
Answer
Here is an example of an iterator:
iterator Gen(start: int) yields (x: int)
yield ensures |xs| <= 10 && x == start + |xs| - 1
{
var i := 0;
while i < 10 invariant |xs| == i {
x := start + i;
yield;
i := i + 1;
}
}
An instance of this iterator is created using
iter := new Gen(30);
It is used like this:
method Main() {
var i := new Gen(30);
while true
invariant i.Valid() && fresh(i._new)
decreases 10 - |i.xs|
{
var m := i.MoveNext();
if (!m) {break; }
print i.x;
}
}
Here the method MoveNext
and the field xs
(and others) are automatically created,
as decribed in the reference manual.
Note that the syntax of iterators is under discussion in the Dafny development team and may change or have additional alternatives in the future.
Can classes appear in specs?
Question
Can classes appear in specs?
Answer
Class types can be argument types for a method or function and the corresponding formal parameter can then be mentioned in specs. Within the specs, you can call functions (ghost or not) of those classes.
However, there are some limitations:
- Primarily, the
new
operator may not be used in a specification, so new class objects cannot be allocated in the spec - Note also that class objects are on the heap; as heap objects they will need to be mentioned in reads clauses.
“How do I write specifications for a lambda expression in a sequence constructor?”
Question
How do I write specifications for a lambda expression in a sequence constructor?
Answer
Consider the code
class C {
var p: (int, int);
}
function Firsts0(cs: seq<C>): seq<int> {
seq(|cs|, i => cs[i].p.0) // Two errors: `[i]` and `.p`
}
Dafny complains about the array index and an insufficient reads clause in the lambda function. Both of these need specifications, but where are they to be written.
The specifications in a lamda function expression are written after the formal aarguments
but before the =>
.
The array index problem is solved by a requires
clause that limits the range of the index::
class C {
var p: (int, int);
}
function Firsts0(cs: seq<C>): seq<int> {
seq(|cs|, i requires 0 <= i < |cs| => cs[i].p.0) // Two errors: `[i]` and `.p`
}
and the reads complaint by a reads
clause that states which objects will be read.
In this case, it is the objects cs[i]
that have their p
field read.
If the element type of cs
were a value type instead of a reference type, this
reads
clause would be unnecessary.
class C {
var p: (int, int);
}
function Firsts2(cs: seq<C>): seq<int>
reads set i | 0 <= i < |cs| :: cs[i]
{
seq(|cs|, i
requires 0 <= i < |cs|
reads set i | 0 <= i < |cs| :: cs[i] => cs[i].p.0)
}
I have a lemma and later an assert stating the postcondition of the lemma, but it fails to prove. Why and how do I fix it?
Question: I have a lemma and later an assert stating the postcondition of the lemma, but it fails to prove. Why and how do I fix it?
I have this lemma
lemma MapKeepsCount<X,Y,Z>(m : map<X,Y>, f : (X) -> Z)
requires forall a : X, b : X :: a != b ==> f(a) != f(b)
ensures |m| == |map k <- m.Keys :: f(k) := m[k]|
and later on this code
MapKeepsCount(schema, k => Canonicalize(tableName, k));
assert |schema| == |map k <- schema.Keys | true :: Canonicalize(tableName, k) := schema[k]|;
The final assert fails, even though it exactly matches the ensures of the lemma. What am I missing?
If the lemma is an axiom, one can try to assume the post condition right before the assertion. But that failed in this case
MapKeepsCount(schema, k => Canonicalize(tableName, k));
assume |schema| == |map k <- schema.Keys | true :: Canonicalize(tableName, k) := schema[k]|;
assert |schema| == |map k <- schema.Keys | true :: Canonicalize(tableName, k) := schema[k]|;
Which makes no sense. I even put the function into a variable, and this still fails
assume |schema| == |map k <- schema.Keys :: fn(k) := schema[k]|;
assert |schema| == |map k <- schema.Keys :: fn(k) := schema[k]|;
Answer:
The explanation is a little involved, and in the end gets into a weakness of Dafny. But these is a workaround. Here goes:
To prove that the |map …|
expression in the specification has the same value as the |map …|
expression in the code,
the verifier would either have to compute the cardinality of each map (which it can’t do, because m.Keys
is symbolic and could stand for any size set)
or reason that the one map …
is the very same map as the other map …
(in which case it would follow that the cardinality of the two maps are also the same).
The way to prove that two maps are equal is to show that they have the same keys and the same mappings.
The idea of proving two things equal by looking at the “elements” of each of the two things is called extensionality.
Dafny never tries to prove extensionality, but it’s happy to do it if you ask it to.
For example, if G
is a function that you know nothing about and you ask to prove
assert G(s + {x}) == G({x} + s + {x});
then Dafny will complain. You have to first establish that the arguments to these two invocations of G
are the same, which you can do with an assert:
assert s + {x} == {x} + s + {x};
assert G(s + {x}) == G({x} + s + {x});
Here, Dafny will prove the first assertion (which it actually does by proving that the sets are elementwise equal) and will then use the first assertion to prove the second.
Going back to your example, Dafny needs to know that the two map
s are equal. To help it along, perhaps you could mention the two in an assertion, like
assert map … == map …;
But you can’t do that here, because the two map expressions are in different scopes and use different variables. To establish that the two maps are equal, we thus need to do something else. If the two of them looked the same, then Dafny would know that the are the same. But the form is slightly different, because you are (probably without thinking about it) instantiating a lambda expression. To make them the same, you could rewrite the code to:
var F := k => Canonicalize(tableName, k);
MapKeepsCount(schema, F);
assert |schema| == |map k <- schema.Keys | true :: F(k) := schema[k]|;
Now, this map …
syntactically looks just like the one in the lemma postcondition, but with schema
instead of m
and with F
instead of f
.
When two map comprehensions (or set comprehensions, or lambda expressions) are syntactically the same like this, then Dafny knows to treat them the same.
Almost.
Alas, there’s something about this example that makes what I said not quite true (and I didn’t dive into those details just now).
There is a workaround, and this workaround is often useful in places like this, so I’ll mention it here.
The workaround is to give the comprehension a name. Then, if you use the same name in both the caller and callee,
Dafny will know that they are the same way of constructing the map.
The following code shows how to do it:
lemma MapKeepsCount<X, Y, Z>(m: map<X, Y>, f: X -> Z)
requires forall a: X, b: X :: a != b ==> f(a) != f(b)
ensures |m| == |MyMap(f, m)|
ghost function MyMap<X, Y, Z>(f: X -> Y, m: map<X, Z>): map<Y, Z>
requires forall a <- m.Keys, b <- m.Keys :: a != b ==> f(a) != f(b)
{
map k <- m.Keys :: f(k) := m[k]
}
method Use<X,Y,Z>(schema: map<X,Y>, tableName: TableName)
requires forall a : X, b : X :: a != b ==> Canonicalize(tableName, a) != Canonicalize(tableName, b)
{
var F := k => Canonicalize(tableName, k);
MapKeepsCount(schema, F);
assert |schema| == |MyMap(F, schema)|;
}
type TableName
function SimpleCanon<K>(t: TableName, k: K): int
It manually introduces a function MyMap
, and by using it in both caller and callee, the code verifies.
Why can’t I write ‘forall t: Test :: t.i == 1’ for an object t?
Question:
Why can’t I write forall t: Test :: t.i == 1
for an object t?
Answer:
This code
trait Test {
var i: int
}
class A {
predicate testHelper() {
forall t: Test :: t.i == 1
// a forall expression involved in a predicate definition is not allowed to depend on the set of allocated references,
}
}
can be better written as
trait Test {
var i: int
}
class A {
ghost const allTests: set<Test>
predicate testHelper() reads allTests {
forall t: Test <- allTests :: t.i == 1
}
}
That way, if you want to assume anything about the Test classes that you are modeling extern, you only need to specify an axiom that says that whatever Test you have was in allTests, which could have been a pool of Test objects created from the start anyway, and then you can use your axiom.
How do I say ‘reads if x then this`y else this`z’? Dafny complains about the ‘this’.
Question:
How do I say ‘reads if x then this`y else this`z’? Dafny complains about the ‘this’.
Answer:
Here is some sample code that show a workaround.
trait Test {
var y: int
var z: int
function {:opaque} MyFunc(x: bool): int
reads (if x then {this} else {})`y, (if x then {} else {this})`z {
if x then y else z
}
}
How do I model extern methods that return objects?
Question:
How do I model extern methods that return objects?
Answer:
When modeling extern functions that return objects, it’s usually not good to have specifications that return objects. It’s better to have a predicate that takes the input of a function, an object, and relates the two to each other.
For example:
trait {:extern} {:compile false} Test {
var i: int
var y: int
}
trait {:extern} {:compile false} Importer {
function Import(i: int): (r: Test)
ensures r.i == i
method {:extern} {:compile false} DoImport(i: int) returns (r: Test)
ensures r == Import(i)
predicate Conditions(i: int) {
&& var r := Import(i);
&& r.y == 2
}
}
In this case, it’s better to write a predicate, and use existential quantifiers along with the :|
operator,
and there is no need to prove uniqueness because we are in ghost code!
trait {:extern} {:compile false} Test {
var i: int
}
trait {:extern} {:compile false} Importer {
predicate IsImported(i: int, r: Test) {
r.i == i
}
method {:extern} {:compile false} DoImport(i: int) returns (r: Test)
ensures IsImported(i, r)
predicate Conditions(i: int) {
&& (exists r: Test :: IsImported(i, r))
&& var r :| IsImported(i, r); // Note the assignment has changed.
&& r.y == 2
}
}
How do I tell Dafny that a class field may be updated?
Question
I get a “call might violate context’s modifies clause” in the following context. I have a field in a class that is is an array whose elements are being modified by a call, but the field does not exist when the enclosing method is called. So how do I tell Dafny that it can be modified?
Here is an example situation:
class WrapArray {
var intarray: array<int>;
constructor (i:int)
requires i > 0
{
this.intarray := new int[i];
}
method init(i: int)
modifies intarray
{
var index: int := 0;
while (index < intarray.Length){
intarray[index] := i;
index := index+1;
}
}
}
method Main()
{
var sh:= new WrapArray(5);
sh.init(4);
}
Answer
When dafny is asked to verify this, it complains about the call sh.init
that it modifies objects that
Main does not allow. Indeed sh.init
does modify the elements of sh.intarray
and says so in its modifies
clause,
but that array does not even exist, nor is sh
in scope, in the pre-state of Main
.
So where should it be indicated that sh.intarray
may be modified?
The key is in the fact that neither sh
nor sh.intarray
is allocated in Main
’s pre-state. Main
should be allowed
to modify objects that are allocated after the pre-state. Indeed Main
knows that sh
is newly allocated, so its fields
may be changed. That is, we are allowed to assign to sh.intarray
. But here we want to change the state of sh.intarray
,
not sh
. The array is newly allocated, but Main
does not know this.
After all, it is possible that the constructor initialized sh.intarray
with some existing array and changing that array’s elements
would change the state of some other object. We need to tell Main
that the constructor of WrapArray
allocates a new
array of ints. The syntax to do that is to add a postcondition to the constructor that says fresh(intarray)
.
Writing the constructor like this
constructor (i:int)
requires i>0
ensures fresh(intarray)
{
this.intarray := new int[i];
}
solves the problem.
“Why does Dafny not know this obvious property of maps?”
** Question: Why does Dafny not know this obvious property of maps?
I have this simple program:
method mmm<K(==),V(==)>(m: map<K,V>, k: K, v: V) {
var mm := m[k := v];
assert v in mm.Values;
}
The value v
has just been inserted into the map. Why can’t Dafny prove that v
is now an element of the map?
** Answer
Dafny does not include all possible properties of types in its default set of axioms. The principal reason for this is that including all axioms can give Dafny too much information, such that finding proofs becomes more time-consuming for all (or most) problems. The trade-off is that the user has to give hints more often.
In this particular example, in order for Dafny to prove that v
is in mm.Values
, it needs to prove that
exists k': K :: k' in mm.Keys && mm[k'] == v
. This is a difficult assertion to prove; the use of the axiom is not triggered
unless there is some term of the form _ in mm.Keys
present in the assertions. So the proof is made much easier if we
first assert that k in mm.Keys
; then Dafny sees immediately that k
is the k'
needed in the exists expression.
So
method mmm<K(==),V(==)>(m: map<K,V>, k: K, v: V) {
var mm := m[k := v];
assert k in mm.Keys;
assert v in mm.Values;
}
proves just fine.
I can’t prove the equivalence between the method part of a function by method
` and the function itself
Question
I can’t prove the equivalence between the method part of a function by method and the function itself. It seems that my invariants can’t be maintained by the loop, and I don’t know how to prove them.
Answer
Consider the simple problem of computing the sum of a sequence of integers. You might be tempted to immediately write the following equivalence, with your best guess of an invariant and a hint at the end to help Dafny realize that the result is correct. However you cannot prove the invariant you just wrote.
function Sum(s: seq<int>): (result: int) {
if |s| == 0 then
0
else
s[0] + Sum(s[1..])
} by method {
result := 0;
for i := 0 to |s|
invariant result == Sum(s[0..i])
// ^^^^^^^^^^^^^^^^^^^^^^
// Cannot be proved
{
result := result + s[i];
}
assert s[0..|s|] == s;
}
Let’s unroll the computation of the function on a sequence of 3 elements. The function will compute:
s[0] + (s[1] + (s[2] + 0))
But the loop will compute
((0 + s[0]) + s[1]) + s[2]
In the function, we add the first element (s[0]
) to the result of computing the sum of the remaining elements (s[1] + (s[2] + 0))
).
In the by method, we add the last element (s[2]
) to the accumulator, which contains the sum of the initial terms ((0 + s[0]) + s[1]
).
If it was not the case that the addition was associative and 0 was a neutral element, there would be no immediate way to prove that the two computations are equivalent.
There are essentially three solutions around that:
- Improve the invariant, knowing
+
is associative - Change the order of computation of the function so that it matches the by method
- Change the order of computation of the by method so that it matches the function
There are more intrusive solutions, such as making the function tail-recursive by changing the function’s signature to include an accumulator or a sequence of callbacks to perform a the end, but we will explore only the one that don’t change the signature of Sum()
.
Improved invariant
You can change the invariant to be invariant result + Sum(s[i..]) == Sum(s)
, as below:
function Sum(s: seq<int>): (result: int) {
if |s| == 0 then
0
else
s[0] + Sum(s[1..])
} by method {
result := 0;
for i := 0 to |s|
invariant result + Sum(s[i..]) == Sum(s) // New invariant
{
result := result + s[i];
}
} // No hint needed at the end
lemma IntermediateProperty(result: int, result': int, i: int, s: seq<int>)
requires 0 <= i < |s|
requires result' == result + s[i]
requires result + Sum(s[i..]) == Sum(s)
ensures result' + Sum(s[i+1..]) == Sum(s)
{
calc {
Sum(s);
== result + Sum(s[i..]); // Requires definition
== result + (s[i] + Sum(s[i+1..])); // Definition of Sum()
==(result + s[i]) + Sum(s[i+1..]); // Associativity
== result' + Sum(s[i+1..]); // Definition of result'
}
}
This works because, with result'
being the result at the end of the loop and +
being associative,
the lemma IntermediateProperty()
shows the underlying reasoning that helps prove that the invariant
is indeed invariant. Dafny can prove it automatically, so the lemma is not needed in the loop body.
One nice thing is that we can get rid of the final hint.
What if you had an operation more complex that “+”, that is not associative? This is when you need to ensure the loop and the function are computing in the same order. Let’s explore how to do so by changing either the function, or the by-method body.
Make the function compute what the by-method does
The by-method loop’s first addition is 0 plus the first element (s[0]
) of the sequence. For this to
be the first addition performed by the function, it has to be at the bottommost level of the call.
Indeed, each addition is performed after the recursive call finishes. This means that
the function needs to sum the n-1
elements first and add the remaining last one.
Since it’s exactly what the method computes, it satisfies our initial invariant.
function Sum(s: seq<int>): (result: int) {
if |s| == 0 then
0
else
Sum(s[0..|s|-1]) + s[|s| - 1]
// We add the last element to the sum of the first
} by method {
result := 0;
for i := 0 to |s|
invariant result == Sum(s[0..i])
{
assert s[0..i+1][0..i] == s[0..i];
// Minimum hint needed for proof
result := result + s[i];
}
assert s[0..|s|] == s;
} // One last hint
Not only does this approach require more proof hints, but it might also break the proofs that dependend on the shape of the function, while all we wanted in the first place was to give a more efficient implementation to the function. Therefore, it’s reasonable to expect we will prefer to change the implementation of the by-method body to reflect the function, not the opposite, as follows:
Make the by-method body compute what the function computes
To compute iteratively what the function computes recursively, you have to find what is the first
addition that will be computed by the method. As mentioned previously, the first addition is the one performed at the bottommost level of recursion: the first addition is s[|s|-1] + 0
,
so the loop has to actually be in reverse, like this:
function Sum(s: seq<int>): (result: int) {
if |s| == 0 then 0 else s[0] + Sum(s[1..])
} by method {
result := 0;
for i := |s| downto 0 // Reverse. First i == |s| - 1
invariant result == Sum(s[i..]) // The invariant looks like the function
{
result := s[i] + result; // Note how we sum in reverse as well.
}
} // No hint needed at the end
Note that this approach results in the smallest invariant that actually closely matches the function itself.
Also, instead of adding to the right of result
, adding to the left ensures the same order is kept,
in case the operation was not commutative (so that it would work for sequence append operation).
Is there a Dafny style? and a Dafny linter (style checker and bad smell warnings)?
Question
Is there a Dafny style? and a Dafny linter (style checker and bad smell warnings)?
Answer
There is a Dafny style guide here.
There is not yet a Dafny lint tool (that is, warnings about technically correct but suspicious or poor-style code), though a formatter is underway. Warnings about some matters are included in the Dafny parser. However, ideas for lint warnings are being collected and you are welcome to contribute ideas: suggestions can be made on the issues list.
Is Dafny available as a library, to be called from other software?
Question
Is Dafny available as a library, to be called from other software?
Answer
Yes, it is. The DafnyPipeline library on NuGet is the most likely candidate for inclusion in a third-party program.
How do I run boogie manually?
Question
How do I run Boogie manually? What Dafny output and command-line flags do I need?
Answer
A Boogie file is generated by Dafny using the option -print
. For example, the command dafny -print:a.bpl HelloWorld.dfy
will produce a file a.bpl
.
If the -print
option lacks an argument (the file name), the somewhat confusing message Error: No input files were specified
is emitted.
Be cautious: dafny -print A.dfy B.dfy
may overwrite A.dfy
.
You can also use -print:-
to send the boogie file to the standard output.
To run boogie, it is most convenient to install boogie directly. See https://github.com/boogie-org/boogie. Dafny invokes Boogie as a library, not as a spawned executable, so there is no Boogie executable in the Dafny installation. However, the version of Boogie that Dafny uses corresponds to Boogie 2.15.7 (as of Dafny 3.7.3).
On a simple Hello World program, boogie a.bpl
is sufficient. Dafny does rely on these default Boogie options
smt.mbqi
is setfalse
model.compact
is setfalse
model.v2
is settrue
pp.bv_literals
is setfalse
Dafny also sets these non-default Boogie options:
auto_config
is setfalse
type_check
is settrue
smt.case_split
is set3
smt.qi.eager_threshold
is set100
smt.delay_units
is settrue
smt.arith.solver
is set2
These all however are subject to change, especially as the version of Boogie used changes
In addition, Dafny sends a variety of other command-line options to Boogie, depending on selections by the user and heuristics built-in to Dafny. Some guide to the available (Dafny) options that are passed through to Boogie are in the reference manual.
Does Dafny verify methods in parallel?
Question
Does Dafny verify methods in parallel?
Answer
When used on the command-line, Dafny verifies each method in each module sequentially
and attempts to prove all the assertions in a method in one go.
However, you can use the option /vcsCores
to parallelize some of the activity
and various options related to verification condition splitting can break up the work
within a method.
When used in the IDE, the default is concurrent execution of proof attempts.
Is there a doc generator for Dafny?
Question
Is there a doc generator for Dafny?
Answer
Not one produced by the Dafny team or included in a Dafny release. This 3rd-party tool was reported by users: https://github.com/nhweston/dfydoc.
How can I improve automation and performance for programs with non-linear arithmetic?
Question
How can I improve automation and performance for programs with non-linear arithmetic?
Answer
There are some switches (/arith and the somewhat deprecated /noNLarith) that reduce the automation you get with nonlinear arithmetic; they improve the overall proof success by using manually introduced lemmas instead. There are now also many lemmas about nonlinear arithmetic in the Dafny standard library.
It looks like, when compiling to C#, my print statements don’t show up if I don’t have \n at the end of the string.
Question
It looks like, when compiling to C#, my print statements don’t show up if I don’t have \n at the end of the string.
Answer
The desired output is present in all current Dafny backends. But note that
if the print statement does not include the \n
, then the output may not either.
In that case the output may be (depending on the shell you are using)
concatenated with the prompt for the next user input.
For example,
method Main() {
print "Hi";
}
produces (with a bash shell)
mydafny $ dafny run --target=cs Newline.dfy
Dafny program verifier finished with 0 verified, 0 errors
Himydafny $
Is there a standard library for Dafny?
Question
Is there a standard library for Dafny?
Answer
No, but one is planned. Some sample code is at https://github.com/dafny-lang/libraries. Contributions and ideas are welcome.
Why do I need to use an old version of Z3?
Question
Why do I need to keep using an old version of Z3?
Answer
It is correct that the version of Z3 used by Dafny (through Boogie) is an old version. Although the Dafny team would like to upgrade to newer versions of Z3 (to take advantage of bug fixes, at a minimum), so far the newer versions of Z3 perform more poorly on Dafny-generated SMT for many test cases.
How do I ask a question or file a problem report or make a suggestion about Dafny?
Question
How do I ask a question or file a problem report or make a suggestion about Dafny?
Answer
You can ask questions about Dafny
- on Stack Overflow, tagged as ‘dafny’: https://stackoverflow.com/questions/tagged/dafny
You can report issues
- On the Dafny Issues log: https://github.com/dafny-lang/dafny/issues
Documentation about Dafny is available at https://dafny.org and links from there.
Any plans to release the language server as a NuGet package? Seems like it’s not part of the Dafny release.
Question
Any plans to release the language server as a NuGet package? Seems like it’s not part of the Dafny release.
Answer
It is now available on NuGet, along with other components of the Dafny: (https://www.nuget.org/packages?q=dafny):
What compiler target langages are in development?
Question
What compiler target langages are in development?
Answer
As of version 3.7.3
- C#, Javascript, Java, and Go are well-supported
- Python is under development
- Limited support for C++ is available
- Rust support is being planned
“Error: z3 cannot be opened because the developer cannot be verified”
This error occurs on a Mac after a new installation of Dafny, with Z3. It is a result of security policies on the Mac.
You can fix the result by running the shell script allow_on_mac.sh
that is part of the release.
The problem can arise with other components of Dafny as well.
“Error: rbrace expected”
The error “rbrace expected”
is a common occurence caused by some parsing error within a brace-enclosed block, such as a module declaration, a class declaration, or a block statement.
The error means that the parser does not expect whatever characters it next sees. Consequently, the parser just says that it expects the block to be closed by a right curly brace (}
).
Indeed, one cause might be an inadvertently omitted right brace.
Here are some other examples:
- A misspelled keyword introducing the next declaration ``` module A { method m() {} mthod n() {} }
- A `const` initializer follows ':=', not '='
module A { const x: int= 4; }
- A field (`var`) does not take an initializer
class B { var x: int := 5 }
- A field (`var`) does not take an initializer, and if it did it would follow a `:=`, not a `=`
class A { var x: int = 5; }
# "Error: closeparen expected"
## Question
What causes the error "Error: closeparen expected" as in
```dafny
method test(int i) {}
producing
ERROR_CloseParen.dfy(1,12): Error: closeparen expected
1 parse errors detected in ERROR_CloseParen.dfy
Answer
You are writing a Java/C parameter declaration. In Dafny, parameter declarations have the form name: type
, so
method test(i: int) { ... }
“Error: cannot establish the existence of LHS values that satisfy the such-that predicate”
Here is example code that produces this error:
method PickKey<K, V>(m: map<K, V>) returns (ret: K) {
var k :| k in m;
return k;
}
When a such-that (:|
) initialization is used, Dafny must be able to establish that there is at least one value
that satisfies the predicate given on the RHS.
That is, in this case, it must prove
assert exists k :: k in m;
.
But for this example, if the map m
is empty, there is no such value,
so the error message results.
If you add a precondition that the map is non-empty, then the error is gone:
method PickKey<K, V>(m: map<K, V>) returns (ret: K)
requires |m.Keys| > 0
{
var k :| k in m;
return k;
}
“Error: type parameter 0 (K) passed to type A must support no references”
Ordinarily, a type parameter X
can be instantiated with any type.
However, in some cases, it is desirable to say that X
is only allowed to be instantiated by types that have certain characteristics. One such characteristic is that the type does not have any references.
A “reference”, here, refers to a type that is or contains a reference type. Reference types are class and trait types. So, if a type parameter is restricted to only “no reference” types, then you cannot instantiate it with a class type or a trait type.
A datatype can also include a reference. For example,
datatype MyDatatype = Ctor(x: MyClass)
More subtly, a type
datatype D
If you’re getting the “no reference” error, then you’re either trying to write an unbounded quantifier over a type that may contain references, or you’re trying to use a type that may contain references to instantiate a type parameter restricted to no-reference types.
Type characteristics that a type parameter must satisfy are written in parentheses after the type name and are separated by commas. For example, to say that a type parameter X
must not contain any references, you would declare it as X(!new)
. To further ensure it supports compile-time equality, you would declare it as X(!new,==)
.
Presumably, you’re trying to instantiate a type parameter like X(!new)
with a type that may contain references.
There is more discussion of type parameter characteristics in the reference manual.
“Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got map<int, A>)”
Here is example code that produces the given error message:
class A {}
method test(m: map<int,A>)
modifies m;
{
}
The expression in the modifies clause is expected to be a set of object references.
It is permitted also to be a comma-separated list of object references or sets or sequences of such references.
In this example, the expression is none of these; instead it is a map
.
map
s are values and so are not modified; new values are created, just like an integer is not modified one computes a different integer value.
If the intent here is to say that any of the A
objects stored in the map may be modified, then one has to construct a set of all those objects.
For a map, there is an easy way to do this: just say m.Values
, as in this rewrite of the example:
class A {}
method test(m: map<int,A>)
modifies m.Values;
{
}
“Error: name of datatype (String) is used as a function?”
How do I fix this error message: “name of datatype (String) is used as a function”?
module MString {
export provides String
datatype String = String(s: string)
}
module MX {
import opened MString
const S := String("asd")
}
The names visible in module MX
are the datatype String
but not its constructor, since
the dataype is only imported as provides
.
Consequently, the only option for the name String
in module MX
is that datatype,
which then causes the error message.
The fix to this is to declare the export as export reveals String
.
If String
is meant to be opaque (only provided) then you cannot construct elements of it;
if it is meant to be transparent, then you must reveal it.
“Error: possible violation of function precondition for op(v)”
Here is code that provoked this error (though the error message as been made more specific in later releases):
ghost function Eval(): string -> bool {
EvalOperator(Dummy)
}
ghost function EvalOperator(op: string -> bool): string -> bool
{
(v: string) => op(v)
}
function Dummy(str: string): bool
requires str == []
The problem has to do with arrow types.
In particular here, the argument of EvalOperator
takes a ->
function, which is a total, heap-independent function.
However, its argument, Dummy
, is a partial, heap-independent function, because it has a precondition.
If you want EvalOperator
to be flexible enough to take partial functions, then declare op
to have the type
string --> bool
.
There is more on arrow types in the reference manual;
“Error: type ? does not have a member IsFailure”
The IsFailure
member is a necessary part of failure-compatible types, which are used with the :-
operator.
See the discussion in the reference manual for more detail.
“Error: value does not satisfy subset constraints of T”
The error “value does not satisfy subset constraints of T”
for some type name T
arises when a value is trying to be converted to a subset type T
,
and the value cannot be proved to satisfy the predicate that defines the subset type.
This is pretty clear when one is trying to assign, say an int
to a nat
, but is more complex when using generic types.
This example
type neg = r : real | r <= 0.0
datatype formula<T> =
| Var(z: T)
| Plus(x: formula<T>, y: formula<T>)
| Minus(x: formula<T>, y: formula<T>)
| Mult(x: formula<T>, y: formula<T>)
| Divide(x: formula<T>, y: formula<T>)
function method toReal(x: formula<real>) : real
{
match x
case Var(z) => z
case Plus(y, z) => toReal(y) + toReal(z)
case Minus(y, z) => toReal(y) - toReal(z)
case Mult(y, z) => toReal(y) * toReal(z)
case Divide(y, z) =>
if toReal(z) == 0.0 then 42.0 else 43.0
}
datatype ChildLineItem = ChildLineItem(negChargeAmount: formula<neg>)
predicate isValidChildLineItem(l: ChildLineItem)
{ toReal(l.negChargeAmount) <= 0.0 }
produces
ERROR_Covariance.dfy(24,11): Error: value does not satisfy the subset constraints of 'formula<real>'
Dafny program verifier finished with 2 verified, 1 error
The problem is that the code is trying to convert a formula<neg>
to a formula<real>
.
While a neg
is a subtype of real
, that does not imply a subtype relationship between
formula<neg>
and formula<real>
.
That relationship must be declared in the definition of formula
.
By default, the definition of a generic type is non-variant, meaning there is no
subtype relationship between formula<T>
and formula<U>
when T
is a subtype of U
.
What is wanted here is for formula
to be covariant, so that
formula<T>
is a subtype of formula<U>
when T
is a subtype of U
.
For that, use the declaration formula<+T>
.
To declare formula
as contravariant use formula<-T>
. Then formula<U>
is a subtype of formula<T>
when T
is a subtype of U
.
Type parameter characteristics are discussed in the reference manual
“Error: function precondition might not hold”
This error can occur when trying to write a sequence comprehension expression like
function f(i: int): int
requires i < 10
{
i
}
method test() {
var s := seq(5, i => f(i));
}
which produces
ERROR_SeqComp.dfy(8,23): Error: function precondition might not hold
ERROR_SeqComp.dfy(2,13): Related location
Dafny program verifier finished with 0 verified, 1 error
The problem is that current Dafny does not implicitly impose the condition that the function used to initialize the
sequence elements is only called with nat
values less than the size of the new sequence. That condition has to be made explicit:
function f(i: int): int
requires i < 10
{
i
}
method test() {
var s := seq(5, i requires i < 10 => f(i));
}
“Error: insufficient reads clause to invoke function”
Example: This code
class {:autocontracts} A {
ghost predicate Valid() {
true
}
constructor() {
// no-op
}
}
class {:autocontracts} B {
var things: set<A>
ghost predicate Valid()
reads things
{
forall thing | thing in things :: thing.Valid()
}
constructor() {
things := {};
}
}
produces this output:
ERROR_InsufficientReads.dfy(17,48): Error: insufficient reads clause to invoke function
Dafny program verifier finished with 3 verified, 1 error
This error message indicates that a nested call of a function needs a bigger reads
set than its enclosing function provides.
Another situation provoking this error is this:
class A {
var x: int
predicate IsSpecial() reads this {
x == 2
}
}
type Ap = x : A | x.IsSpecial() witness *
In this case the error message is a bit misleading. The real problem is that the predicate in the subset declaration (that is, x.IsSpecial()
)
is not allowed to depend on the heap, as IsSpecial
does. If such a dependency were allowed, then changing some values in the heap could
possibly change the predicate such that a value which was allowed in the subset type now suddenly is not. This situation would be a disaster for both
soundness and ease of reasoning.
Another variation on the above is this example:
trait A { var x: int }
type AZero = a: A | a.x == 0 witness *
where again the predicate depends on a heap variable x
, which Dafny does not permit.
And a final example:
datatype Foo = Foo | Foofoo
class Bar {
var foo: set<Foo>;
function method getFoo(): set<Foo> { this.foo }
}
which produces Error: insufficient reads clause to read field
. In this case the function getFoo
does indeed have an insufficient reads clause, as
it does not have one, yet it reads a field of this
. You can insert either reads this
or reads this`foo
before the left brace.
The code in the original question is fixed like this:
class A {
predicate Valid() reads this {
true
}
constructor() {
// no-op
}
}
class B {
var things: set<A>
predicate Valid()
reads this, things
{
forall thing | thing in things :: thing.Valid()
}
constructor() {
things := {};
}
}
Cannot export mutable field ‘x’ without revealing its enclosing class ‘A’
An example of this error is the code
module M {
export
provides A,
A.foo, // want to export foo, which refers to x
A.x // to make export set self-consistent, need to export x
class A {
var x: int
function method foo(): int
reads this
{
x
}
}
}
which produces the error
ERROR_MutableField.dfy(5,19): Error: Cannot export mutable field 'x' without revealing its enclosing class 'A'
1 resolution/type errors detected in ERROR_MutableField.dfy
By only providing A
, importers will know that A
is a type,
but won’t know that it is a reference type (here, a class).
This makes it illegal to refer to a mutable field such as in the reads clause.
So, you have to export A by revealing it.
Note, export reveals A
does not export the members of A
(except, it does export the anonymous constructor of A, if there is one).
So, you still have control over which members of A to export.
The following code verifies without error:
module M {
export
reveals A
provides
A.foo, // want to export foo, which refers to x
A.x // to make export set self-consistent, need to export x
class A {
var x: int
function method foo(): int
reads this
{
x
}
}
}
“Error: this symbol not expected in Dafny”
This error message is not clear and may come from a variety of sources. Here is one:
lemma L() {}
method test()
ensures L(); true
{
}
which produces
ERROR_PostconditionLemma.dfy(4,15): Error: this symbol not expected in Dafny
1 parse errors detected in ERROR_PostconditionLemma.dfy
The error message points to the token true
as the unexpected symbol.
true
is definitely a legitimate symbol in Dafny.
The problem is that the ;
in the ensures
clause is seen as the (optional) semicolon that can end
the clause. Thus the true
is interpreted as the (illegal) start to a new clause (or a {
to start the body).
The correct way to include a lemma with the postcondition is to use parentheses: `ensures (L(); true)
“Prover error: Unexpected prover response (getting info about ‘unknown’ response): (:reason-unknown ‘Overflow encountered when expanding old_vector’)”
This error is caused by a bug in the Z3 backend tool used by Dafny.
As of v3.9.0 there is work underway to update Z3 to a more recent version.
Until then, the best you can do is to try to change the verification condition sent to Z3 by splitting it up, using various Dafny options and attributes like {:split_here}
, {:focus}
, /vcsSplitOnEveryAssert
, /vcsMaxSplits
, and /randomSeed
.
“Duplicate name of import: …”
This error results from importing two modules with the same name. For example
import A.Util
import B.util
In this case, the default name given to the two imports is the same: Util
.
To give them different names, use the longer form of the import statement
import A.Util
import BU = B.Util;
Now a name N
from A.Util
can be referred to as Util.N
and
a name N
from B.Util
can be referred to as BU.N
.
“Warning: /!\ No terms found to trigger on.”
This warning occurred with the following code:
predicate ExistsSingleInstance(s : string32, delim : string32)
{
exists pos : nat ::
(pos <= |s| - |delim| && forall x : nat :: x < |delim| ==> s[pos + x] == delim[x]) &&
forall pos' : nat :: (pos' <= |s| - |delim| && forall y : nat :: y < |delim| ==> s[pos' + y] == delim[y]) ==> pos == pos'
}
The verifier uses quantifications by finding good ways to instantiate them.
More precisely, it uses forall
quantifiers by instantiating them and it proves exists
quantifiers by finding witnesses for them.
The warning you’re getting says that nothing stands out to the verifier as a good way to figure out good instantiations.
In the case of pos
, this stems from the fact that a good instantiation would be some pos
for which the verifier already knows either pos <= …
or forall x :: …
, the former of which is not specific enough and the latter is too complicated for it to consider.
The “no trigger” warning is fixed by this refactoring:
predicate SingleInstance(s: string, delim: string, pos: nat)
{
pos <= |s| - |delim| &&
forall x : nat :: x < |delim| ==> s[pos + x] == delim[x]
}
predicate ExistsSingleInstance'(s: string, delim: string)
{
exists pos : nat ::
SingleInstance(s, delim, pos) &&
forall pos' : nat :: SingleInstance(s, delim, pos') ==> pos == pos'
}
One more remark: The “no trigger” warning should be taken seriously, because it’s usually a sign that there will be problems with using the formula and/or problems with verification performance.
“Error: value does not satisfy the subset constraints of ‘(seq, Materials.EncryptedDataKey) -> seq' (possible cause: it may be partial or have read effects)"
Here is an example of submitted code that produced this error:
function EncryptedDataKeys(edks: Msg.EncryptedDataKeys): (ret: seq<uint8>)
requires edks.Valid()
{
UInt16ToSeq(|edks.entries| as uint16) + FoldLeft(FoldEncryptedDataKey, [], edks.entries)
}
function FoldEncryptedDataKey(acc: seq<uint8>, edk: Materials.EncryptedDataKey): (ret: seq<uint8>)
requires edk.Valid()
{
acc + edk.providerID + edk.providerInfo + edk.ciphertext
}
The general cause of this error is supplying some value to a situation where (a) the type of the target (declared variable, formal argument) is a subset type and (b) Dafny cannot prove that the value falls within the predicate for the subset type. In this example code, uint8
is likely a subset type and could be at fault here.
But more likely and less obvious is supplying FoldEncryptedDataKey
as the actual argument to FoldLeft
.
The signature of FoldLeft
is function {:opaque} FoldLeft<A,T>(f: (A, T) -> A, init: A, s: seq<T>): A
.
Note that the type of the function uses a ->
arrow, namely a total, heap-independent function (no requires or reads clause).
But FoldEncryptedDataKey
does have a requires clause. Since ->
functions are a subset type of partial, heap-dependent ~>
functions,
the error message complains about the subset type constraints not being satisfied.
These various arrow types are described in the release notes when they were first added to the language. They are also documented in the reference manual.