Sec 2.1.5 How Arithmetic Sequences Work? Generalizing Arithmetic Sequences.
Design by Contract Advanced Software Tools Seminar Alexander Freidin 2006 Defining Contracts on...
-
date post
22-Dec-2015 -
Category
Documents
-
view
212 -
download
0
Transcript of Design by Contract Advanced Software Tools Seminar Alexander Freidin 2006 Defining Contracts on...
Design by Contract
Advanced Software Tools SeminarAlexander Freidin
2006
Defining Contracts on Method Call Sequences
Outline
Design by Contract – reminder
What is missing in DbC?
JASS overview
Trace-Assertions
Design by Contract - overview
Proposed by Bertrand Meyer for Eiffel.
Goal – organize communication between software elements.
How? By specifying mutual obligations and benefits – contracts.
Two sides involved in contract are: Supplier – supplies services Client – receives services from the supplier
More on Contracts
Client Supplier relationship. Not another item in specification
document, but a part of the program code.
Contract either annotates the code or a special language construct like in Eiffel.
Checked for violation in runtime. Unlike assertions, contract is separated
from the business logic.
Design by Contract facilities
Preconditions – Obligation for the client. Specify the constraints on the permissible
program state or passed arguments. Must hold before calling the supplier.
Postconditions – Obligation for the supplier. Supplier guarantees on completion of the task.
Example: Supplier – Square root routine for real number. Precondition – input is a non-negative number. Postcondition – output is an approximation,
within a specified precision, of the exact mathematical square root of the input number.
Design by Contract facilities
Class invariants – Describe the consistency and integrity
properties of the class and its instances.
Should hold in all client-visible states.
Example: Vector size must be non-negative.
Design by Contract facilities
Loop variants and invariants
Catch the typical errors in loops: The loop doesn’t terminate. “Off by one” errors. One extra/missing
iteration Special cases like zero iterations are
not handled.
Design by Contract facilities
Loop invariants – Keep integrity through loop execution. Must be satisfied:
at the beginning of the loop after every loop iteration when the loop has terminated
Loop variants – Ensures loop termination. Integer expression decreased every loop
iteration, but limited to be non-negative.
Design by Contract – facilities
Check instruction – checks if the certain property is
satisfied at the certain stage of the computation.
Implemented as one or more assertion clauses inside a method.
Design by Contract extensions
First-order logic quantifiers – helpful for contracts definition over sets: Universal quantifier: “for all” Existential quantifier: “there exists“
Refinement checks – Check if the subclass is a behavioral subtype of
its superclass. Preconditions are weakened. Postconditions are strengthened. Superclass invariant must be preserved.
Design by Contract Pros
Helps ensure correctness Helps debugging Helps testing Helps ensure inheritance is properly
handled Provides a quite effective form of
documentation
Design by Contract Cons
DbC is not a panacea, must be used with care.
Not all specifications can be described with existing facilities of DbC. Example: DbC doesn’t support specifications that
define performance issues such as execution time and required resources – performance contracts.
Checking contract violation may be more time consuming than the method execution.
Example: Class that works on Hamiltonian cycle graphs. Its preconditions need to solve NPC problem.
Note on Performance contracts
Difficult to ensure and test
Have to be defined properly Min/Max/Average measurement? Can be relaxed if under load?
Ongoing research
JAVA-MaC – monitors and checks program execution against requirements specification. Time between events is also part of specification.
What is left out DbC?
Classical DbC facilities scale well with stateless classes.
Stateful class behavior depends on its state.
Explicit state – visible by the client, i.e. returned by a public method. Can be utilized in pre/post-conditions.
Implicit state – invisible by the client. Cannot be expressed by classical DbC constructs.
Stateful class example
Class implementing I/O with some device. Methods: connect, disconnect, read,
write. Specification: To start I/O with device,
one must call “connect” method. I/O is done with “read/write” methods. To finish working, one must call “disconnect” method.
FSM of the example specification
JASS – Java with ASSertions
Pre-compiler tool written in Java. Translates annotated contracts into
dynamic checking code. Violation of specification is indicated
by Java exception. Free of charge. Website:
http://semantic.Informatik.Uni-Oldenburg.de/~jass
JASS – DbC Features
Standard DbC features: Pre/post-conditions Class invariants Loop variants / invariants Check instruction
Advanced features: Refinement, i.e. subtyping Existential and universal quantifiers Trace assertions – novel feature
Trace Assertions - Goal
Goal – define the valid order of methods invocation.
Going back to previous example: class implementing I/O with some device.
Trace Assertions
To support classical DbC, the above class should: Keep track of its state. Expose the state with the public
getState() method. Each pre/post-condition must include
state checks. Stands against DbC concept contract
logic must not be part of the business logic.
Trace Assertions
Trace Assertions extend DbC in respect of defining contracts for valid order of method calls.
Keep trace of objects behavior. Throw Java exception if trace violates the specification.
Filling the hole of behavior contracts in classical DbC.
Sequence of method calls is called trace.
Trace-Assertions
Allowed traces are specified by CSP-like (Communicating Sequential Processes) processes.
CSP is a notation describing concurrent system, whose components, called processes, interact by communication.
Communicating Sequential Processes
A CSP process: Independent entity with interfaces for interaction
with processes/environment. Defined in terms of events, which are basic
elements in CSP.
Event containing more than one piece of information is called compound event. E.g. gate.open
Process a P will execute event “a” and then behave as process P.
We will not show CSP semantics here, but observe how the trace assertions are defined on CSP notation base.
Trace-Assertions
Trace-Assertion example:init().b init().e start().b start().e
Method start() can be only invoked after init() finished execution.
Suffix ‘.b’ indicates the begin of a method and ‘.e’ indicates the end accordingly.
Nested call of start() from inside init() will result in Trace-Assertion violation.
Trace-Assertions are class invariants
Trace-Assertions describe the global behavior, therefore they are part of the class invariant in JASS.
Syntax:/** invariant[AssertionName] trace (trace-assertion body);**/
Processes
Trace-Assertions contain one or more declarations of processes.
Process describes the valid behavior of a class at runtime.
Processes are defined by: Process name Process parameters Local variables Process expression
Basic Processes
Basic Processes: STOP – no further method invocations
are allowed.
ANY – any method invocation is allowed.
TERM – the actual object must terminate. Introduced to comply with CSP termination definition. Unused.Mapped to this.finalize() STOP.
Trace-Alphabet
Trace-Alphabet is a set of method names.
Alphabet is defined: Implicitly – a set of method names that
appear in process definitions.
Explicitly – a list of method names specified at the header of Trace-Assertion definition.
Trace-Alphabet – implicit definition
Example:trace(
init() STOP);
Trace-Alphabet for this example is implicit: { init() }.
Trace <init() init()> is invalid, but <init() start()> is valid. Method start() is unknown to Trace-Assertion.
Trace-Assertion checks are limited byTrace-Alphabet.
Trace-Alphabet – explicit definition
Alphabet is defined in trace clause Trace { m1, m2, …, mN }
Example:/** invariant
trace { init(), start() }(
init() STOP);
**/
Trace-Alphabet – common wildcards
this.* - all methods of the belonging class.
* EXCEPT init() – all methods, but init()
{ public A.*, public B.* } – all public methods of class A and B
M(*) – all methods M with any parameters
M(?) – all methods M with one parameter
M(int, ?, *) – all methods M with at least two parameters. First parameter must be of type ‘int’.
Processes
Valid behavior of a program is described by process declarations.
Starting point of Trace-Assertion is process called MAIN.
/** invariant trace { public this.* } (MAIN() {
init() CALL Initialized() }Initialized() {
* EXCEPT init() CALL Initialized() });
**/
First method call must be init() and no more init() invocations allowed.
Choice Operator
Previous examples are limited to accept a single sequence of method invocations.
Choice operator <|> defines branches or ‘choice points’ of allowed processes.
Example:MAIN() {
(a() b() STOP) <|> (a() c() STOP)}
Means: after a() either b() or c() may be invoked.
Valid traces are: a(), a() b(), a() c().
Parallelism operator
If a class should satisfy more than one single flow, the parallel-operator |<>| is used.
Example:
MAIN() {CALL P() |<>| CALL Q() }
P() { a() b() STOP }
Q() {a() c() STOP
}
Valid traces are: a(), a() b(), a() c(), a() b() c(), a() c() b().
Both processes are evaluated in parallel.
Process Variables
Syntax of process declaration is derived from Java method declaration.
As Java methods, processes can have arguments and variables.
Example:MAIN() {
init() CALL P(“initialized”) }
P(String status) {String msg = “Status:” + status;m() …
}
Process Variables
Local variables must be declared at the beginning of the process declaration.
Variables use cases:
Process definition can depend on conditions. Variables can store program state to define complex conditions.
Processes can execute arbitrary Java code that uses the variables. E.g. Printing status messages.
Variables can be used to define branches between processes (if-else).
Conditional method invocations
Trace-Assertions can bind certain condition to any method invocation.
That is unlike pre/post-conditions, each invocation of the same method may have certain condition.
Example:MAIN() {
CALL Counter(0)}Counter(int num) {
m() WHERE(num < 3) CALL Counter(num+1)}
Method m() may be invoked at most three times.
The condition given after WHERE must hold before m() is executed.
Execution of Java code
Trace-Assertions allow execution of arbitrary Java code.
Purposes: To allow definition of complex conditions. To allow program state monitoring.
Monitoring example #1:
MAIN() {EXECUTE(System.out.println(“init”);) init() ANY }
The message “init” is printed at the beginning of init() execution.
Execution of Java code
Monitoring example #2:
MAIN() {EXECUTE(System.out.println(“init done”);) init().e ANY }
The message “init done” is printed by the end of init() method.
Conclusion: The execution code is always bound to the next process event.
Branches – If/Else
Trace-Assertions can have branches.
Example:IF(b) {
CALL P() } ELSE {
CALL Q()}
Allow to express complex dynamical behavior of a program.
Variables are useful to branch the trace-assertion checking flow.
Data Exchange
Trace-Assertions support exchanging argument values between the running program and the Trace-Assertion.
There are two types of data exchange: Read the method’s argument value into the
process. Restrict the values of the method arguments.
Data Exchange: program process
To read the argument value into the local variable of a process, it has to be preceded with ‘?’.
Example:MAIN() {
String s;boolean b;m(?s, ?b) WHERE(s != null) CALL Q(b)
}
m(?s, ?b) yields to m(String, boolean) method. Any ?x must be a declared process variable.
The notation ‘?x’ is called data exchange. The value of the argument is passed from the program to process variable x.
Data Exchange: process program
The Trace-Assertion is able to restrict the possible values passed to the methods.
Restriction can be specified with a constant or process local variable.
Constant restriction: m(“x”), e.g. m(7) – the method m() is allowed to receive only the value of 7.
Variable restriction: m(!x) – the argument should have the value of x.
Data Exchange: restricting arguments values
There are multiple ways of restricting method arguments values.
If the restrictions are static, then preconditions are preferred for this task.
All the examples are equivalent in semantics:
P() { m(7) STOP }Q() { int i = 7; m(!i) STOP }R() { int i; m(?i) WHERE(i==7) STOP }
Data Exchange – method result value
Trace-Assertions support passing the result value from a method to the process: ?ret m().
Trace-Assertions can restrict the method’s return value to the value from the process: !val m().
Misleading example:P() {
boolean b = false;?b m() WHERE(b) CALL Q()
}
WHERE-expression is evaluated at the beginning of method m(), not at the end as expected.
Data Exchange – method result value
To use the returned result value, one should use If/Else-expression.
Example:P() {
boolean b = false;?b m() IF(b) {
CALL Q() } ELSE { CALL E() }
}E() {
EXECUTE(throw new RuntimeException();) STOP }
Observing recursive method calls
The class Factorial will calculate the factorial of positive integer by recursively calling the method “factorial”.
Each recursive factorial call will initiate a process that will accept a call to another factorial only if the parameter has been reduced but not less than zero.
Observing recursive method calls
Summary
Design by Contract is a powerful technique for getting the implementation according to specification.
Classical DbC is incomplete. There is a place for research.
JASS – powerful tool that implements DbC principles for Java.
Trace-Assertions – a novel and powerful feature of JASS.