[REBOL] Design by contract
From: dankelg8:cs:man:ac at: 7-Feb-2001 14:13
Here's a Design By Contract script that I hacked together yesterday.
For those who don't know, Design By Contract is a software pattern used to
enforce preconditions and postconditions of a function.
For example, in Rebol there's no way currently to define your own types.
A function that does vector multiplication can look like this:
vector-mul: func [v1 [block!] v2 [block!]] [...]
The problem here is that a block can contain anything.
DBC offers a solution to this:
vector-mul: cfunc [v1 [block!] v2 [block!]] [
Here's what it could look like:
vector-mul: cfunc [a [block!] b [block!]] [
(length? a) = (length? b)
fold func [x y] [(number? x) and y] true a
fold func [x y] [(number? x) and y] true b
(length? cres) = (length? a)
fold checks if all the elements of the block are numbers.
cres is the result of evaluating the function body.
If either the pre- or postcondition fails, an error will be thrown.
>> vector-mul [1 2 none 4] [3 4 5 6]
** User Error: Precondition violated!
** Near: vector-mul [1 2 none 4] [3 4 5 6]
Fold above is defined like:
fold: func [
foreach element series [res: combine element res]
Preconditions and postconditions can be turned off such that cfunc will
return a normal func.
So if speed is critical, the tests can be done while debugging.
Anyway, here's the code.
Hopefully someone of you have got a better version or have ideas of how to
make it better.
There are a few problems with this one, e.g. cres is in the global context
my-func: cfunc .... as above
Title: "Design by contract"
my-squareroot: cfunc [
x >= 0
(cres * cres) = x
contract: make object! [
pre-check: post-check: false
enforce: does [pre-check: post-check: true]
set 'cfunc func [
/local new-body new-args
if pre-check [
insert body compose/deep [if not all
[(pre-conditions)] [throw make error! "Precondition violated!"]]
if post-check [
body: compose/deep [cres: do [(body)]]
append body compose/deep [
if not all [(post-conditions)] [throw make
error! "Postcondition violated!"]
if all [any [pre-check post-check] not find/only arguments
[catch]] [insert/only arguments [catch]]
func arguments body