if
, while
,
:=
, class
, ...
function
,
datatype
,
codatatype
, ...
Lemma
,
calc
,
refines
,
inductive
predicate
, ...method between (p: int, r: int) returns (q: int)
requires r-p > 1
ensures p < q < r
{
q := (p+r) / 2;
}
method MultipleReturns(x: int, y: int)
returns (more: int, less: int)
ensures less < x
ensures x < more
{
more := x + y;
less := x - y;
}
Does this program meet the specification?
Try it online: https://rise4fun.com/Dafny
method MultipleReturns(x: int, y: int)
returns (more: int, less: int)
requires 0 < y
ensures less < x
ensures x < more
{
more := x + y;
less := x - y;
}
var
keyword, and can optionally have type
declarations:
var x:int;
var x := 0;
var x:int, y:nat;
var x, y : int;
Exercise: Encode the following example in Dafny and read the error messages.
method m1() {
var a := 0;
a := 1;
var a := 2;
var b:int;
var c;
var d:int, e:bool := 0;
var f, g := 0, false;
var h, i:int;
}
method Triple(x: int) returns (r: int)
ensures r == 3*x
{
var y := Double(x);
r := y + x;
}
method Double(x:int) returns (r:int)
ensures r == 2*x
This follows our discussion on Design by Contract.
Try it online: https://rise4fun.com/Dafny
This is related to our discussion on Design by Contract from previous lectures.
Exercise: Write a method Max that takes two integer parameters and returns their maximum. Add appropriate annotations and make sure your code verifies.
method Abs(x: int) returns (y: int)
ensures 0 <= y
{
if x < 0 {
return -x;
} else {
return x;
}
}
method TestAbs() {
var v := Abs(3);
assert 0 <= v;
}
Assertions can be introduced at any point. An assertion says that a particular expression always holds when control reaches that part of the code.
Exercise: Add
assert v == 3
to the end of the method TestAbs
.
Make changes so that the assertion is valid.
method Abs(x: int) returns (y: int)
ensures 0 <= y
{
if x < 0 {
return -x;
} else {
return x;
}
}
method TestAbs() {
var v := Abs(3);
assume v==3;
assert 0 <= v;
assert v==3;
}
Assumptions can be introduced at any point.
function abs(x: int): int
{
if x < 0 then -x else x
}
method m2()
{
assert abs(3) == 3;
}
function abs(x: int): int
{
if x < 0 then -x else x
}
method m2()
{
assert abs(3) == 3;
}
Exercise: Change your specification of
the method Abs
to use this function.
Exercise:
Write a function max
that returns the larger of two given integer
parameters. Write a test method using an assert that tests your function.
Exercise:
Change the specification of the method Max
to use your new function.
We are not going into much detail for now, but it is possible to compile Dafny programs. Example:
method Main()
{
print("Hello World\n");
}
To verify, compile, and run the program:
dafny /compile:3 Main.dfy
function
method
are compiled and can be
called from real code.Exercise: Change your test method for
Max
to capture the value of
max
to a variable, and then do the checks
from the exercise using the variable.
Dafny will reject this program because you are calling
max
from real code. Fix this problem using
a function method
.
Exercise: Define the Fibonacci function and write a method with assertions that test your function.
The Fibonacci function is defined as:
fib(0)=0fib(1)=1fib(n)=fib(n−1)+fib(n−2)for n>1invariant
to identify loop invariants:method m4(n: nat)
{
var i := 0;
while i < n
invariant 0 <= i
{
i := i+1;
}
assert i==n;
}
Question: Is the assertion at the end of the loop valid? If not, how can we fix it?
Exercise: Write a method Exp
that takes an integer m, a natural
n, and returns mn. Write the specification in
terms of a separate, recursive function
exp
.
Exercise: Consider the following function definition:
function fib(n: nat): nat
{
if n == 0 then 0 else
if n == 1 then 1 else fib(n - 1) + fib(n - 2)
}
Turning this function into a function method would be extremely slow, as this version of calculating the Fibonacci numbers has exponential complexity.
Write a verified iterative algorithm that computes the nth Fibonacci number.