1 / 49

Design by Contract

Design by Contract. Defining Contracts on Method Call Sequences. Advanced Software Tools Seminar Alexander Freidin 2006. Outline. Design by Contract – reminder What is missing in DbC? JASS overview Trace-Assertions. Design by Contract - overview. Proposed by Bertrand Meyer for Eiffel.

heath
Download Presentation

Design by Contract

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Design by Contract Defining Contracts on Method Call Sequences Advanced Software Tools Seminar Alexander Freidin 2006

  2. Outline • Design by Contract – reminder • What is missing in DbC? • JASS overview • Trace-Assertions

  3. 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

  4. 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.

  5. 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.

  6. 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.

  7. 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.

  8. 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.

  9. 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.

  10. 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.

  11. Design by Contract Pros • Helps ensure correctness • Helps debugging • Helps testing • Helps ensure inheritance is properly handled • Provides a quite effective form of documentation

  12. 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.

  13. 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.

  14. 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.

  15. 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.

  16. FSM of the example specification

  17. 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

  18. 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

  19. Trace Assertions - Goal • Goal – define the valid order of methods invocation. • Going back to previous example: class implementing I/O with some device.

  20. 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.

  21. 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.

  22. 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.

  23. 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.

  24. 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.

  25. 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 ); **/

  26. 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

  27. 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.

  28. 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.

  29. 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.

  30. Trace-Alphabet – explicit definition • Alphabet is defined in trace clause • Trace { m1, m2, …, mN } • Example: /** invariant trace { init(), start() } ( init()  STOP ); **/

  31. 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’.

  32. 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.

  33. 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().

  34. 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.

  35. 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()  … }

  36. 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).

  37. 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.

  38. 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.

  39. 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.

  40. 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.

  41. 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.

  42. 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.

  43. 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.

  44. 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 }

  45. 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.

  46. 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 }

  47. 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.

  48. Observing recursive method calls

  49. 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.

More Related