Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

Design by contract

 [1/4] 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!]] [ <preconditions> ][ <function body> ][ <postconditions> ] 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 ][ <function body> ][ (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 [ combine [any-function!] init [any-type!] series [series!] /local res ][ res: init foreach element series [res: combine element res] 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 Usage: contract/enforce my-func: cfunc .... as above REBOL [ Title: "Design by contract" Date: 6-feb-2001 Example: [ my-squareroot: cfunc [ x [number!] ][ x >= 0 ][ square-root x ][ (cres * cres) = x ] ] ] contract: make object! [ pre-check: post-check: false enforce: does [pre-check: post-check: true] set 'cfunc func [ arguments [block!] pre-conditions [block!] body [block!] post-conditions [block!] /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!"] return cres ] ] if all [any [pre-check post-check] not find/only arguments [catch]] [insert/only arguments [catch]] func arguments body ] ]

 [2/4] from: chaz:innocent at: 8-Feb-2001 19:56


This is cool! Seems like this information plus the stuff in the thread in "[REBOL] Writing a protocol -- a mini intro" would lead to a function that only will run when words meeting its preconditions appear in the port it is monitoring. chaz At 02:13 PM 2/7/01 +0000, you wrote:

 [3/4] from: sanghabum:aol at: 21-Feb-2001 15:10


Gisle Dankel wrote:
> 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. > <snip>
Thanks for this script. Tools for validating parameters are something sadly lacking in Rebol as it stands today, and could do with being built into the language. If Carl were to look at Eiffel he'd get an idea of the strength that such inbuilt capability would bring. As I try to write robust code, I typically find myself writing stuff like this little function: UpdateTuple: func [ "Add/Subtracts M from the Nth part of a tuple" Tup [Tuple!] "Tuple to update" Nth [Integer!] "Nth part of tuple (leftmost is 1)" Val [Integer!] "Value to add/subtract from Tuple" ] [ either all [(Nth > 0) not (Nth > Length? Tup) ] ; all [poke tup Nth ((pick tup Nth) + val) ] ;either true [ CrashOut "UpdateTuple" "Nth is out of range" ] ; either false ]; func I give Rebol top marks for built-in documentation and parameter type specification. That's the first seven or so lines of the above function. But the payload (a single line) is then embedded in another seven or so lines of parameter checking. In Eiffel, the payload and the parameter checking would be distinct. (Crashout is another little function of mine, not shown, that tries to shutdown gracefully while advising the user not to panic). Colin

 [4/4] from: m:koopmans2:chello:nl at: 22-Feb-2001 7:16


Hi, I missed the design by contract script? Could any of you guys mail it to me? Thanks, Maarten