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