CSC151, Class 10: Documentation: Preconditions, Postconditions, and Other Related Issues Overview: * Why document? * Where to document? * The six P's. * Robustness: Exiting upon error. * Example: sum-of-squares. * Husk-and-kernel programming. * Lab Notes: * Toaster pastries * HW1 due. * Writeup 2 assigned. * How to spell in Linux: Use spell. * Differences between (let (...) (lambda (...) ...)) and (lambda (...) (let (...) ...))? * Any other reflections on yesterday's lab? ---------------------------------------- (define sum-of-squares (let ((square (lambda (x) (* x x)))) (lambda (ls) (if (null? ls) 0 (+ (square (car ls)) (sum-of-squares (cdr ls))))))) (define sum-of-squares (lambda (ls) (let ((squares (lambda (x) (* x x)))) (if (null? ls) 0 (+ (square (car ls)) (sum-of-squares (cdr ls))))))) ---------------------------------------- Good Programmers Document (First!) * No one's code is as clear as they think. Documentation helps other people repair or improve your code. * Evidience suggests that "other people" includes yourself after a few months. * Helps you understand your code. If you describe what you want to do first, you can make sure that you're doing "the right thing". * Tells other people what your code is supposed to do, so they can use it without understanding how you've done it. Where to document? * Before each procedure: What it does. * Within each procedure: Complex code. * A "reader's guide" to each set of code: Overview / relationships Table of contents Question: Does documentation slow the program down? Answer: Nope, not at all. (Well .. compilation may take fractionally longer, but it's a very small fraction.) Today's focus: "Before procedure" documentation * Sam's recommendation: Six P's * IN the future: Choose some documentation style and always do it. * Procedure: Name it sum-of-squares * Parameters: Name them and give them types ls, a list of numbers * Purpose: Short summary of what it does squares all the values in ls and sums them * Produces: Name it and give it a type result, a number * Preconditions: What is required in order for the procedure to work. ls cannot contain complex numbers The sum of the squares of the values of ls must be representable as a number on the computer. * Postconditions: Guarantees about result (usually formal) Adversarial Stance toward Pre/Postcondition design * If you are too casual on your preconditions, someone calling your procedure might choose ones you don't expect. * Lazy programmers want to implement as little as possible What should you do if the preconditions are not met? * Check them, stop and report an error. + Not all preconditions are easily verifiable. * Trust the caller. * Check preconditions and return a special value for "Wrong preconditions" * Throw an exception First variant is easy (error 'procname "message") Reports an error and stops the program (define sum-of-squares (let ((square (lambda (x) (* x x)))) (lambda (ls) (cond ((not (all-numbers? ls)) (error 'sum-of-squares "It's probably my fault, but you seem to have misunderstood that the appropriate parameter was a list of numbers.")) ((null? ls) 0) (else (+ (square (car ls)) (sum-of-squares (cdr ls)))))))) Normal sum-of-squares (without error-checking) takes about N steps for a list of length Na Error-checking version: N steps for first check + N-1 steps for second check + N-2 steps for third check ... + 1 step for final check 1 + 2 + 3 + ... + N-2 + N-1 + N + N + N-1 + N-2 + + 3 + 2 + 1 --------------------------------------- N+1 + N+1 + N+1 + ....+ N+1 + N+1 + N+1 = N(N+1) sum we wanted: N(N+1)/2 Fixing it Version 1: Check a little at a time (define sum-of-squares (let ((square (lambda (x) (* x x)))) (lambda (ls) (cond ((null? ls) 0) ((not (number? (car ls))) (error 'sum-of-squares "Feh")) (else (+ (square (car ls)) (sum-of-squares (cdr ls)))))))) Version 2: Husk-and-Kernel (define sum-of-squares (lambda (ls) (if (not (all-numbers? ls)) (error 'sum-of-squares "Learn how to type") (sum-of-squares-kernel ls)))) (define sum-of-squares-kernel (let ((square (lambda (x) (* x x)))) (lambda (ls) (if (null? ls) 0 (+ (square (car ls)) (sum-of-squares (cdr ls)))))))