78
www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

Embed Size (px)

Citation preview

Page 1: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Fundamentals of Perfect Developer

A one-day hands-on tutorial

Page 2: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Outline• Session 1: Getting Started

– Configuring Perfect Developer and creating a project– Expressions, types, constants, functions, properties– Classes, data, invariants, functions, schemas,

constructors

• Session 2: Going Further – Interfacing to a Java front-end– Sequences and recursion

• Session 3: Refining methods and data– Statement lists, statement types, loops, nested

refinement.– Internal data, retrieve functions

• Session 4: Inheritance– Derived and deferred classes– Defining and redefining inherited methods

Page 3: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Configuration

• Configure Perfect Developer to use the chosen editor– Load the Project Manager– Select Options…Editor– Browse to the editor executable file– Select the editor type

• Configure the editor to recognise Perfect Developer files– See instructions in the Editor Customizations folder of

the Perfect Developer installation

Page 4: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Creating a project

• Click on the New toolbar icon

• Browse to a writable folder, enter a project name, click Save and then OK

• Create a new file called Examples

• Add text: property (a, b, c: int) pre a < b, b < c assert a < c;

• Save the file

• Save the project and click the Verify tool

Page 5: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Some predefined classes

• bool

• char

• int

• real

• set of X

• bag of X

• seq of X

• map of (X -> Y)

Set, bag, sequence and map types are finite collections.

See Quick Reference or Language Reference Manual for more details (e.g. commonly-used

members)

Page 6: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Expressions

• All the usual arithmetic operators

• a < b < c means what you would expect it to

• a / b (integer) and a % b have precondition b > 0

• a / b (integer) rounds towards -

• a .. b yields the sequence {a, a+1, a+2 … b}

• #c yields the cardinality or length of the collection c

• a # c yields the number of occurrences of a in c

Page 7: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Booleans, Conditionals etc.• Boolean connectives:

& | ==> <== <==>

• Conditional expression:( [a > 0]: a, [b > 0]: b, []: 0)

• Let-declaration:( let t ^= a - b; t * t )

• Embedded assertion:( assert a > 0, b > 0; a / b )

• The whole shebang:( let t ^= a - b; assert t > 0; [t > 10]: 1, []: 10 / t )

Page 8: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Constructor calls

• A constructor call yields a value of the specified type

• Without parameters:seq of int{}MyClass{}

• With parameters:seq of int{a, b, c}MyClass{42}

• Some constructors have preconditions that must be metint{s} is ok when s = "123" but not when s = "lemon" !

[precondition is: ~s.empty & (forall c::s :- c.isDigit)]

Page 9: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Quantifiers etc.• If c is of type set of T, bag of T or seq of T,

and p(x) is any Boolean expression involving x:

Expression Return type

forall x::c :- p(x) boolforall x: T :- p(x)

exists x::c :- p(x) boolexists x: T :- p(x)

that x::c :- p(x) Tany x::c :- p(x)

those x::c :- p(x) set / seq / bag of T

for x::c yield v(x) set / seq / bag of type of v

for those x::c :- p(x) yield v(x)

Page 10: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Declaring constants and functions

• Declaring a constant:const four: int ^= 2 + 2;

const smallPrimes: seq of int ^= those x::2..100 :- ~(exists y::2..<x :- x % y = 0);

const two ^= 2;

• Declaring a function:function half(x: int): int

pre x > 0 ^= x / 2;

Precondition (if needed)

Type can be omitted in simple cases

Page 11: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Declaring properties

• Use property declarations to express theorems: property assert half(four) = two;

property (x: int) pre x > 0, x % 2 = 0 assert half(x) < x, (let h ^= half(x); h + h = x);

Implicit universal quantification over the parameters

Givens to be assumed

Consequences to be proved

Page 12: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Exercise 1: express the following

• All the integers from 0 to 100 inclusive, in ascending order. Verify that your solution contains 42 but does not contain 101.

• The integer j (which is known to be greater than 0) divides the integer i exactly.

• The squares of all the prime numbers from 2 to 100 inclusive.

• The highest integer in a set S of integers that is known to be non-empty

Page 13: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Declaring enumerations

class Currency ^= enum unspecified, euro, pound, USdollarend;

const localCurrency ^= pound@Currency;

… localCurrency.toString …

Page 14: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Declaring a Class

abstract

internalconfined

interface

variables, invariants,methods, constructors

[never mind for now]

access redeclarations,methods,constructors,properties

[never mind for now]

Variables declared here form the abstract data model of the class

Invariants here constrain the data

These methods and constructors are for use by confined and/or interface methods and constructors

Access redeclarations allow abstract variables to be directly accessed from outside the class

These methods and constructors can be called from outside the class

Only the interface section is mandatory

class Money ^=

end;

Page 15: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Declaring data and invariants

abstract

var amt: int, ccy: Currency;

invariant amt = 0 | ccy ~= unspecified@Currency;

Variable amt is of type int

Variable ccy is of type Currency

Restriction on the values of amt and ccy

Page 16: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Functions and Operators

function worthHaving: bool ^= amt > 0;

function plus(m: Money): Money pre m.ccy = ccy ^= Currency{amt + m.amt, ccy} assert result.ccy = ccy;

operator (n: int) * : Money ^= Currency{amt * n, ccy};

No “()” if no parameters Return type

Result expression

Optional postassertion

Name

Optional precondition

Use nonmember prefix for methods & properties with no self object

Operator declarations are the same as function declarations apart from the header

Page 17: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Declaring Schemas

nonmember schema swap(a!, b!: Money)

pre a.ccy = b.ccy post change a,b satisfy a’=b, b’=a assert a.plus(b) = b’.plus(a’);

schema !inflate(howMuch: int) pre 0 < howMuch < 200 post amt! = (amt * howMuch)/100;

No “()” if no parameters

Parameter is modified

Postcondition includes frame

This one modifies instance variables

Short for: change amt satisfy amt’= (amt * howMuch)/100

No self object

Page 18: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Declaring Constructors

build{a: int, c: Currency} pre a > 0 post amt! = a, ccy! = c;

build{!amt: int} post ccy! = euro@Currency;

build{} ^= Money {0, unspecified@Currency};

Note parameter list in “{}”

Initialise instance variable directly from the parameter

Postcondition must initialise all instance variables*

We do use “{}” if no parameters

This constructor is defined in terms of another one

Short for:change amt satisfy amt’= a

*except for variables whose when-guards are false

Page 19: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Using access redeclarations

• abstract variables may be redeclared in the interface:function v1; makes v1 readableselector v2; makes v2 readable and writable

• Making a variable writable is generally a bad idea– Except for “convenience” classes, e.g. class pair

• Making a variable of a complicated type readable is generally a bad idea– Because we can’t then change its representation easily

• Constants may be redeclared as nonmember functions

• Use access redeclarations sparingly!

Page 20: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Exercise 2: Specification(followed by coffee break)

• You have been provided with a Perfect specification of class Money

• Try to verify it (there will be 3 verification errors)

• Fix the specification to remove the verification errors

• Verify that multiplying a Money object by 2 is equivalent to adding it to itself

• Declare a “+” operator that works like the “plus” function except that if the amount of either operand is zero, we don’t care what the corresponding currency is

Page 21: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Using Perfect with a graphical UI

Java front-end Perfect back-end

function f (…)

schema ! s (…)

Button 1

Button 2

class Application ^=interface

class MyAppimplements ActionListener

MyApp() build{}constructor calls

when pressed callswhen pressed calls

Best to avoid preconditionsin methods called from Java!

Page 22: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Using Perfect with a graphical UI

• Declare a Perfect class Application– Declare interface functions/schemas to call from Java– Declare an interface constructor to call from Java

• In the graphical interface code:– Import Application.java– Instantiate a single Application object during

initialisation– Call member functions/schemas when buttons are

pressed– Convert parameter types as necessary

• We have provided you with a sample– In file TutorialExample.java

Page 23: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Exercise 3: Build the sample program

• Open project TutorialExample.pdp

• Verify the project

• Click the Build tool icon

• Check for error messages

• Locate and run output\App.jar

• Try making your own changes to Application.pd– e.g. print some of the expressions you wrote earlier

[tips follow…]

Page 24: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Tips

• To use constants and functions from Examples.pd:– Add file Examples.pd to the project– Add to Application.pd: import "Examples.pd";

• You can convert any expression to a string– By calling .toString on it

• To make your application robust:– Verify your version of Application.pd– Don’t add any preconditions to the methods called from

Java!

Page 25: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Sequences and Strings • The standard collection types are:

set of X, bag of X, seq of X (where X is any type you like)string seq of char

• Members of class seq of X include:head tail front back append(x) prepend(x) ++(s) #

(x)intake(n) drop(n) slice(offset, length)isndec isninc permndec permninc isOrdered(cp) !sort(cp)findFirst(x) findLast(x)

• Useful global functions include:flatten(ss: seq of seq of X) interleave(ss, s)

• See the Library Reference for details

Page 26: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Recursive and templated functions

function reverse(s: seq of class T): seq of T decrease #s ^= ( [#s <= 1]: s, []: reverse(s.front).prepend(s.last) );

Indicates that T can be any type

Recursion variant Recursive call

Page 27: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Recursion variants

• General form is:decrease e1, e2, e3 …

• e1, e2 … are of int, bool, char or an enumeration type

• The variant must decrease on each recursive call– Either e1 must decrease– Or e1 stays the same and e2 decreases– Or e1 and e2 stay the same and e3 decreases…

• Integer components must not go negative

Page 28: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Exercise 4: SequencesSpecify the following functions:

• numLeadingSpaces(s: string): nat – returns the index of the first character in s that is not

a space, or the length of s if it is all spaces

• removeLeadingSpaces(s: string): string– returns s with any leading spaces removed

• firstWord(s: string): string– returns the leading characters of s up to but not

including the first space character in s

• splitIntoWords(s: string): seq of string– splits the sentence s into individual words

(hint: use recursion!)

Page 29: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Lunch break!

Page 30: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Refinement

• There are three types of refinement in Perfect:– Refining result expressions to statement lists– Refining postconditions to statement lists– Refining abstract data to implementation data

• When you refine the abstract data of a class, you normally need to refine the method specifications as well

• So we will start with refining specifications

Page 31: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Refining specifications

• Specification refinement serves these purposes:– To implement a specification where Perfect Developer

fails to– To implement a specification more efficiently– To take account of data refinement in affected methods

• You can refine these sorts of specification:– Expressions that follow the “^=” symbol– Postconditions

• To refine a specification, append to it:

via statement-list end

Page 32: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

function square(x: int): int^= x^2via value x*xend;

schema swap(a!, b!: class X)post a!= b, b!= avia let temp ^= a; a! = b; b! = tempend;

Some simple refinements

value statement returns a value from the via..end

Semicolon separates and sequences the statements

A postcondition can be used as a statement

Page 33: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Nested Refinements

• You can refine not just method specifications but also:– Postcondition statements– Let-declarations in statement lists

function fourth(x: int): int ^= x^4 via let x2 ^= x^2 via value x*x end; value x2*x2 end;

value yielded by the inner via..end

value yielded by the outer via..end

Page 34: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Types of Statement• Let-declaration

• Assertion

• Variable declaration

• Postcondition

• pass statement

• If-statement

• value and done statements

• Loop statement

• Block statement

Exactly the same as in bracketed expressions

Omit the “post” keyword!

Does nothing

Same as in postconditions

Page 35: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

If-statement

if

[c in `a`..`z`]: isAletter! = true; valid! = true;

[c in `0`..`9`]: isAletter! = false; valid! = true;

[]: valid! = false

fi

Guard

Statement list

Optional “else” part

[] fi means the same as[]: pass fi

Page 36: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

“value” statementfunction max(a,b,c: class X): X satisfy result >= a & result >= b & result >= c & (result=a | result=b | result=c) via if [a > b]: value max(a, c);

[]: value max(b, c)

fi end;

Every path in an expression refinement must end at a value statement

Page 37: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

“done” statementschema max(a!,b,c: class X) post change a satisfy a’ >= a & a’ >= b & a’ >= c & (a’= a | a’= b | a’= c) via if [a > b]: a!= max(a, c); done;

[] fi;

a!= max(b, c)

end;

A postcondition refinement may contain one or more done statements

Implicit done statement here

Page 38: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Loop statement

// Calculate a^b

var rslt: int! = 1;

loop var j: nat! = 0; change rslt keep rslt’ = a^j’ until j’= b decrease b - j’;

rslt! * b, j! + 1

end;

Loop variant

List of what the loop can change

Start of loop statement

Loop variable declaration

Termination condition

Loop invariant list

Loop body

End of loop statement

Page 39: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Loop statementloop local variable declarations (optional) change list (optional) invariant termination condition (optional) variant body statementsend

• If no change list is given, only the local variables can be changed

• If no termination condition is given, the loop terminates when the variant can decrease no more

Page 40: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Designing loop invariants• Variables in loop invariants may be primed or

unprimed– Primed = current values at the start of an iteration– Unprimed = value before the loop started

• The invariant is the only source of information about current values of changing variables

• The state when the loop completes is given by:invariant & until-part

• The invariant should comprise:– A generalisation of the state that the loop is meant to

achieve;– Additional constraints needed to make the invariant, until-

part, variant and body well-formed

Page 41: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Example of invariant design

• Given s: seq of int we wish to achieve total’= + over s

• Generalise this to tot’= + over s.take(j’) for some loop counter j– When j = #s then the generalisation becomes the

required state because s.take(#s) = s

• This generalisation forms part of the invariant– But s.take(j’) has precondition 0 <= j ’<= #s– So we must either add this precondition as an earlier

invariant…– Or as a type constraint in the declaration of j

Page 42: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Loop example (incorrect)

var totl: int! = 0;

loop var j: int! = 0; change totl keep totl’= + over s.take(j’) until j’= #s decrease #s - j’;

totl! + s[j], j! + 1

end;

Problem! These expressions are not universally well-formed

Page 43: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Loop example (version 1)var totl: int! = 0;

loop var j: int! = 0; change totl keep 0 <= j’<= #s, totl’= + over s.take(j’) until j’ = #s decrease #s - j’;

totl! + s[j], j! + 1

end;

Added this extra invariant at the start

This is now well-formed

This is also well-formed (provided the until-condition is false)

Page 44: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Loop example (version 2)

var totl: int! = 0;

loop var j: (int in 0..#s)! = 0; change totl keep totl’= over s.take(j’) until j’= #s decrease #s - j’;

totl! + s[j], j! + 1

end;

Added this type constraint

This is now well-formed

This is also well-formed (provided the until-condition is false)

Page 45: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

function rev(s: seq of int): seq of int decrease #s ^= ([s.empty]: s, []: rev(s.tail).append(s.head)) via var rslt: seq of int! = seq of int{}; loop var j: (nat in 0..#s)! = 0; change rslt keep rslt’= rev(s.take(j’)) until j’= #s decrease #s - j’; rslt! = rslt.prepend(s[j]), j! + 1 end; value rsltend;

Refining recursion to loops

Page 46: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Refining recursion to loops• Is the preceding example correct?

– Probably!– But Perfect Developer cannot verify it!

• The definition builds the result from front to back– Using append

• The implementation builds the result from back to front– Using prepend

• They are equivalent only because of associativity(a ++ b) ++ c = a ++ (b ++ c) reverse(x.tail).append(x.head) =

reverse(x.front).prepend(x.last)

• To prove this we need an inductive prover!

Page 47: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

function rev(s: seq of int): seq of int decrease #s ^= ([s.empty]: s, []: rev(s.tail).append(s.head)) via var rslt: seq of int! = seq of int{}; loop var j: (nat in 0..#s)! = #s; change rslt keep rslt’= rev(s.drop(j’)) until j’= 0 decrease j’; j! - 1, rslt! = rslt.append(s[j’]) end; value rsltend;

Refining recursion to loops

Page 48: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Loops: a summary

• Getting the invariant correct is critical– It must describe the relationships between all variables

changed by the loop (including the local loop variables)

• Its main part is a generalisation of the desired state after the loop– When the until condition is satisfied, the generalisation

must reduce to the desired state

• You may also need to include constraints on variables– To make expressions in the loop well-formed

• If refining a recursive definition, make sure that the loop builds the result in the same order as the definition

Page 49: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Exercise 5: Method refinement

• Refine the following specifications

function min2(x, y: int): intsatisfy result <= x, result <= y, result = x | result = y;

function findFirst(s: seq of int, x: int): intsatisfy 0 <= result <= #s, result = #s | s[result] = x, forall j::0..<result :- s[j] ~= x;

– Function numLeadingSpaces from exercise 4

– Function splitIntoWords from exercise 4

Page 50: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Data refinement

• When designing a class, we should always use the simplest possible abstract data model– Avoid redundancy!– Don’t be concerned with efficiency at this stage!

• The methods are specified in terms of this model– This keeps the specifications simple!

• The data should not be directly accessible from outside– So we can change the implementation of the data

without changing the class interface– [Except for very simple classes like pair]

Page 51: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Data Refinement (cont’d)

Perfect supports two sorts of data refinement:

• Replacing abstract variables by internal variables– Use a retrieve function to indicate that a variable is replaced– Examples: see Dictionary.pd and Queue.pd in

C:\Program Files\Escher Technologies\Perfect Developer\Examples\Refinement

• Supplementing abstract variables by internal variables– The new internal data adds no new information– Declare internal invariants to specify the relationship– Example: add an index to a data structure– The internal data may be changed even within a function

Page 52: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Data Refinement Example

• We have a class that maintains a list of numbers

• Its constructor creates an empty list

• We provide a method to append a number to the list

• We provide a method to return the sum of all the numbers in the list

Page 53: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

List of integers classfunction sum(s: seq of int): int decrease #s ^= ([s.empty]: 0, []: sum(s.front) + s.last);

class ListOfNumbers ^=abstract var list: seq of int;

interface function list;

build{} post list! = seq of int{};

schema !addNumber(n: int) post list! = list.append(n);

function getSum: int ^= sum(list);

end;

Page 54: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Data Refinement Example

• Suppose that method “sum” is called frequently

• Save time by caching the sum of the list

Page 55: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Refined list of integers classclass ListOfNumbers ^=abstract var list: seq of int;

internal var totl: int;

invariant totl = sum(list);

interface function list;

build{} post list! = seq of int{} via list! = seq of int{}, totl! = 0; end;

Page 56: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Refined list of integers class

schema !addNumber(n: int) post list! = list.append(n) via list! = list.append(n), totl! + n end;

function getSum: int ^= sum(list) via value totl end;

end;

Page 57: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Exercise 6: Data Refinement

• Write a recursive function “longest” which, given a list of strings, returns the longest string in the list (or the empty string if the list is empty, or the latest one of several equal-length longest strings)

• Write a class that maintains a list of strings. You should provide:– A constructor, which sets the list to an empty list– A member schema to append a new string to the list– A member function to return the “longest” string in the

list

• Refine the class to make the implementation of the “longest” member function more efficient

Page 58: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Inheritance

• When declaring a class you can inherit another class– Declare class UniversityMember …– Then class Student ^= inherits UniversityMember …– And class StaffMember ^= inherits

UniversityMember …– And class Professor ^= inherits StaffMember …

• A derived class inherits the variables of its parent– But they are not [normally] visible in the derived class

• A derived class inherits the methods of its parent– But only confined and interface members of the parent

are visible

Page 59: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

The confined section

• The confined section behaves like the interface section– You can put the same types of declaration in it– i.e. Methods, operators, constructors, access

redeclarations– Not constants, variables or invariants

• But confined declarations are only visible within the current class and its descendents– Not to the public at large!– cf. protected in Java and C++

Page 60: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Redefining methods

• Functions, selectors, schemas and operators that are inherited from a parent class may be redefined

• This must be indicated using the redefine keyword

• The parameter and result types in the redefinition must be identical to those in the overridden function

Page 61: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Example of overridingclass UniversityMember ^=abstract var firstNames: seq of string, lastName: string;

interface function getSalary: Money ^= 0; …end;

class StaffMember ^= inherits UniversityMemberabstract var salary: Money;

interface redefine function getSalary: Money ^= salary; …end;

Page 62: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

from types and Dynamic Binding

• You may declare a variable (or parameter, or result) to be of type “from C” where C is a class– e.g. var member: from UniversityMember

• The variable may be assigned a value of type C or any of its descendants– So member may be assigned a value of type Student,

Professor …– “from C” actually means “the union of all non-deferred

classes in the set comprising C and its direct and indirect descendents

• When calling a member function on such a variable, the [re]definition appropriate to the actual type is called– e.g. the relevant version of getSalary

Page 63: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Deferred methods

• You can also declare a method in a class deferred

• The method is left undefined in that class

• This avoids the risk of classes inheriting what may be an unsuitable definition

• The class itself must also be flagged deferred and may not be instantiated

• Descendent classes may define the method using the define keyword

• Any descendent class that does not define it is also a deferred class

Page 64: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Example of deferred methoddeferred class UniversityMember ^=abstract var firstNames: seq of string, lastName: string;

interface deferred function getSalary: Money; …end;

class StaffMember ^= inherits UniversityMemberabstract var salary: Money;

interface define function getSalary: Money ^= salary; …end;

Page 65: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Final classes and methods

• A method can be declared final to prevent it from being redefined in a descendent classfinal function getSalary: Money ^= …

• You can also declare a method final when defining or redefining itdefine final function getSalary: Money ^= …redefine final function getSalary: Money ^= …

• You can declare a class final to mean that no other class may inherit itfinal class Professor ^= …

Page 66: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Some consequences

• If D is a deferred class:var x: D is illegal– But you can use var x: from D

• If F is a final class:var x: from F is illegal– But you can use: var x: F

• If C is a non-final class, f is a final method and g is a non-final method, and given var x: from C :In … x.f … the prover can assume the full postcondition of

fIn … x.g … the prover can assume only the postassertion

of g

Page 67: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Preconditions and inheritance

• When a method is inherited, by default the precondition is inherited too

• You may override the inherited precondition by giving a new one in the method definition or redefinition

• The new precondition must be satisfied whenever the old one would have been satisfied– i.e. you may only weaken the precondition

• To get round this, have the precondition call a method that you can redefine

Page 68: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Inherited precondition example

• Suppose we declare a deferred method isPaid in class UniversityMember

• define this to return false for class Student, true for class StaffMember

• Add precondition pre isPaid to method getSalary

Page 69: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Inherited precondition exampledeferred class UniversityMember ^=abstract var firstNames: seq of string, lastName: string;

interface deferred function isPaid: bool; deferred function getSalary: Money pre isPaid; …end;

class StaffMember ^= inherits UniversityMemberabstract var salary: int;

interface define function isPaid: bool ^= true; define function getSalary: Money ^= salary; …

Page 70: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Inherited precondition example

• That worked OK for class StaffMember, but what about class Student?

• Method getSalary can never be called on class Student because its precondition is always false

• How should we declare it?

Page 71: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Absurd method exampledeferred class UniversityMember ^=abstract var firstNames: seq of string, lastName: string;

interface deferred function isPaid: bool; deferred function getSalary: Money pre isPaid; …end;

class Student ^= inherits UniversityMemberinterface define function isPaid: bool ^= false;

absurd function getSalary; …

Page 72: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Absurd methods

• Declaring a method absurd means that its precondition is always false

• Repeat the parameter list of the method but not its return type

• An absurd method declaration has these consequences:– The method is defined or redefined such that calling it

will raise an exception– A verification condition is generated (i.e. that the

precondition is always false)– It avoids the “Given false, so proof is trivial” warnings

you will otherwise see

Page 73: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Inheritance and postassertions

• When defining or redefining an inherited method, by default the postassertion is inherited

• You may override the postassertion by giving a new one

• The old postassertion must be satisfied whenever the new one is– i.e. you may only strengthen the postassertion

• You can also use: assert …, q – This means assert the inherited postassertion and then

q

Page 74: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Inheritance tips

• When using inheritance, declare methods final where possible– This is not necessary in leaf classes which are declared

final

• For non-final methods of non-final classes, postassertions are very important– Because the prover needs them when the methods are

called on from types– Does not apply to “defining” methods like isPaid

• Only use from types where you really need to allow different types at run-time

Page 75: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Inheritance exercises

• Design a UniversityMember or Employee class hierarchy that reflects the properties and privileges of members of your organisation

• Specify a family of shopping scanners, as outlined at the end of the Shopping Scanner worked example at:

http://www.eschertech.com/teaching/scanner_example.pdf

Page 76: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

What we didn’t cover

• Lots!– after expressions– over expressions– Guarded variable declarations– Selectors– Members of classes set and bag– Declaring templated classes– Other library classes, e.g. map of (X -> Y)– How to solve verification problems– Serialization– Declaring axioms– …

Page 77: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Further Reading

• Perfect Developer 3.0 Language Reference Manual– Start -> Programs -> Perfect Developer ->

Documentation– Or click on the book tool in the Project Manager– Also available at www.eschertech.com

• Online tutorial– via Support -> Self-help section of the web site

• Teaching materials– via Support -> Self-help -> Teaching materials

Page 78: Www.eschertech.com Fundamentals of Perfect Developer A one-day hands-on tutorial

www.eschertech.com

Thank you for participating!