contracts a mystery function
play

Contracts A Mystery Function 1 The Story Your first task at your - PowerPoint PPT Presentation

Contracts A Mystery Function 1 The Story Your first task at your new job is to debug this code written by your predecessor, who was fired for being a poor programmer. int f(int x, int y) { int r = 1; while (y > 1) { if (y % 2 == 1) { r


  1. Contracts

  2. A Mystery Function 1

  3. The Story Your first task at your new job is to debug this code written by your predecessor, who was fired for being a poor programmer. int f(int x, int y) { int r = 1; while (y > 1) { if (y % 2 == 1) { r = x * r; } x = x * x; y = y / 2; This is all you } return r * x; are given } How do you go about this “friendly” challenge? 2

  4. The Language  This code is written in C0 int f(int x, int y) { int r = 1; o The language we will use for most while (y > 1) { of this course if (y % 2 == 1) { r = x * r; }  This is also valid C code x = x * x; o For the most part, C0 programs y = y / 2; } are valid C programs return r * x; o We will use C0 as a gentler } language to  learn to write complex code that is correct  learn to write code in C itself  But what does this function do? 3

  5. The Programmer  Is this good code? int f(int x, int y) { int r = 1; o there are no comments while (y > 1) { o the names are non-descript if (y % 2 == 1) { r = x * r;  the function is called f }  the variables are called x, y, r x = x * x;  No! y = y / 2; } return r * x;  No wonder your predecessor } was fired as a programmer!  But what does this function do? 4

  6. The Function  But what does this function do?  We can run experiments o call f with various inputs and observe the outputs  We do so by loading it in the C0 interpreter – coin The command for The file where we the C0 interpreter saved the function Linux Terminal # coin mystery.c0 C0 interpreter (coin) 0.3.3 'Nickel' (r590, Mon Aug 29 12:04:13 UTC 2016) Type `#help' for help or `#quit' to exit. --> The coin prompt 5

  7. Running Experiments  Call f with various inputs and observe the outputs Linux Terminal We are calling f with # coin mystery.c0 inputs 7 and 12 C0 interpreter (coin) … … The result is 956385313 --> f(7, 12); 956385313 (int) --> f(3, 17); 129140163 (int) --> The result has type int  These are not very good experiments o they don’t help us understand what f does 6

  8. Running Experiments  Call f with various inputs and observe the outputs o we are better off calling f with small inputs o and vary them by just a little bit so we can spot a pattern Linux Terminal Much better! --> f(2, 3); 8 (int) --> f(2, 4); o It looks like f(x, y) computes x y 16 (int) --> f(2, 5); o Let’s confirm with more 32 (int) experiments --> f(2, 6); 64 (int) --> 7

  9. Confirming the Hypothesis  It looks like f(x, y) computes x y  Let’s confirm with more experiments Linux Terminal Yep! That’s x y --> f(2, 2); 4 (int) --> f(3, 2); 9 (int) o We find a secret memo in a --> f(4, 2); hidden drawer 16 (int) --> f(5, 2); Power not working. 25 (int) Fix by tonight or you’re out --> Not the friendliest of work places!  Let’s run a few more experiments to identify the problem 8

  10. Discovering the Bug  f(x, y) is meant to computes x y o but it doesn’t  Let’s find where it fails with more experiments Linux Terminal --> f(-2, 3); It seems to work for It seems to work for -8 (int) negative values of x negative values of x --> f(-2, 2); 4(int) --> f(2, 1); 1 (int) --> f(2, 0); That’s not 2 0 2 (int) --> f(2, -1); That’s definitely not 2 -1 2 (int) -->  Now we have something to chew on 9

  11. Preconditions 10

  12. The Power Function  What does it mean to be the power function x y ? o x * …. * x y times  Yes, but that’s not very precise  Let’s write a mathematical definition x 0 = 1 o x y = x y-1 * x This is a recursive definition and this is its base case 11

  13. The Power Function  What does it mean to be the power function x y ? x 0 = 1 x y = x y-1 * x o What happens if y is negative?  we never reach the base case …  The power function x y on integers is undefined if y < 0 x 0 = 1 This defines x y for y ≥ 0 only This defines x y for y ≥ 0 only x y = x y-1 * x if y > 0 12

  14. int f(int x, int y) { int r = 1; The Power Function while (y > 1) { if (y % 2 == 1) { r = x * r; } x = x * x;  What does it mean to be the power function x y ? y = y / 2; } return r * x; x 0 = 1 } x y = x y-1 * x if y > 0  To implement the power function, f must disallow negative exponents We need to test y. o It can raise an error This would slow f down a bit. o It can tell the caller that the exponent should be ≥ 0 Better! no need to test y 13

  15. Preconditions  Disallow negative exponents o by telling the caller that the exponent should be ≥ 0  A restriction on the admissible inputs to a function is called a precondition o We need to impose // y must be greater than or equal to 0 int f(int x, int y) { a precondition on f int r = 1; o In most languages, while (y > 1) { we are limited to if (y % 2 == 1) { r = x * r; writing a comment }  and hope the caller x = x * x; reads it y = y / 2; This is how we } would write a return r * x; precondition in C } 14

  16. Preconditions in C0  We need to impose a precondition on f o to tell the caller that y should be ≥ 0  In C0 we can write an executable contract directive //@requires y >= 0; int f(int x, int y) //@requires y >= 0; C0 keyword to specify a precondition C0 keyword to specify a precondition { • written between the function header and the body • written between the function header and the body • before the first “{“ • before the first “{“ int r = 1; while (y > 1) { o We check contracts by invoking coin if (y % 2 == 1) { with the -d flag r = x * r; }  “dynamic checking” x = x * x;  but everybody understands it as debug mode y = y / 2; o without the -d flag, contracts are } treated as comments return r * x; } 15

  17. Using Contract Running with contracts disabled Running with contracts enabled Linux Terminal Linux Terminal # coin mystery.c0 # coin -d mystery.c0 C0 interpreter (coin) … C0 interpreter (coin) … --> f(2, 3); --> f(2, 3); 8 (int) 8 (int) --> f(2, -1); --> f(2, -1); 2 (int) mystery.c0:2.4-2.20: @requires annotation failed --> Last position: mystery.c0:2.4-2.20 f from <stdio>:1.1-1.9 --> Contracts are treated as comments Line number where contract failed Contracts are executed File where cc0, the C0 compiler, • if true , execution proceeds normally contract failed works the same way • if false , execution aborts 16

  18. Safety  If we call f(x,y) with a negative y o with -d , execution aborts o without -d , f can return an arbitrary result  there is no right value it could return  Calling a function with inputs that cause a precondition to fail is unsafe o execution will never do the right thing  either abort  or compute a wrong result  The caller must make sure that the call is safe  that y ≥ 0 17

  19. Postconditions 18

  20. Contracts about Function Outcomes  Preconditions are checked before the function starts executing pre  A contract that is checked after it is done function executing could tell us if the function did body the right thing  check that the output is what we expect post o This is a postcondition 19

  21. Postconditions in C0  In C0, the contract directive int f(int x, int y) //@ensures <some_condition> ; //@requires y >= 0; //@ensures …; { C0 keyword to specify a precondition C0 keyword to specify a postcondition • written between the function header and the body • written between the function header and the body int r = 1; • before the first “{“ • after the preconditions (by convention) while (y > 1) { • before the first “{“ if (y % 2 == 1) { allows us to write a postcondition r = x * r; } o <some_condition> can mention the x = x * x; y = y / 2; contract-only variable \result }  what the function returns return r * x;  can only be used with //@ensures } 20

  22. Writing a Postcondition  The postcondition we want to write is //@ensures \result == x**y; o but x**y is not defined in C0 That’s how we write x y in Python  C0 has no primitive power function!  What do we do? o transcribe the mathematical definition into a C0 function int POW(int x, int y) //@requires y >= 0; x 0 = 1 { if (y == 0) return 1; x y = x y-1 * x if y > 0 return POW(x, y-1) * x; } 21

  23. Writing a Postcondition int POW(int x, int y) //@requires y >= 0;  Then our postcondition is { if (y == 0) return 1; //@ensures \result == POW(x, y); return POW(x, y-1) * x; } right? … almost int f(int x, int y) //@requires y >= 0; Linux Terminal //@ensures \result == POW(x,y); # coin -d mystery.c0 { mystery.c0:18.5-18.6:error:cannot assign to int r = 1; while (y > 1) { variable 'x' used in @ensures annotation if (y % 2 == 1) { x = x * x; r = x * r; ~ } Unable to load files, exiting... x = x * x; y = y / 2; o The function modifies x (and y) } return r * y;  Which values of x and y should C0 evaluate the } postcondition with?  We want the initial values, but it is checked when returning … o To avoid confusion, C0 disallows modified variables in postconditions 22

Recommend


More recommend