How does Racket Scheme's "design by contract" features different from Eiffel?
I know that both Eiffel (the progenitor) and Racket both to implement "Design by Contract" features. Sadly, I am not sure how one would different from the other. Eiffel's DBC is reliant on the OOP paradigm and inheritance, but how would Racket, a ver开发者_JAVA百科y different language account for such a disparity?
Racket's main claim to contract fame is the notion of blame, and dealing with ho function is a big part of that for everyday Racket programming, definitely.
You might also want to check out the first two sections of this paper:
http://www.ccs.neu.edu/scheme/pubs/oopsla01-ff.pdf
First of all, your best source of information at this point is the Racket Guide, which is intended as an introductory text rather than a reference manual. Specifically, there is an extensive chapter about contracts that would help. EDIT: Also see the paper that Robby pointed at, he's the main Racket contract guy.
As for your question -- I don't know much about the Eiffel contract system, but I think that it precedes Racket's system. However (and this is again an "IIRC") I think that Racket's contract system was the first one that introduced higher order contracts. Specifically, when you deal with higher order functions assigning proper blame gets a little more complicated -- for example, if you take a foo
function that has a contract of X? -> Y?
and you send it a value that doesn't match X?
then the client code that sent this value to foo
is blamed. But if your function is (X? -> Y?) -> Z?
and the X?
predicate is not satisfied, then the blame goes to foo
itself, not to the client (and if Y?
is not satisfied then the blame is still with the client).
I think you're asking, how could a contract system work without OOP and inheritance? As a user of Racket who is unfamiliar with Eiffel, I'm wondering why a contract system would have anything to do with OOP and inheritance. :)
On a practical level I think of Racket contracts as a way to get some of the benefits of static type declarations, while keeping the flexibility of dynamically typed languages. Plus contracts go beyond just types, and can fill the role of asserts.
For instance I can say a function requires one argument that is an exact integer ... but also say that it should be an exact positive integer, or a union of certain specific values, or in fact any arbitrarily complicated test of the passed value. In this way, contracts in Racket combine what you might do with both (a) type declarations and (b) assertions in say C/C++.
One gotcha with contracts in Racket is that they can be slow. One way to deal with this is to use them at first while developing, then remove them selectively especially from "inner-loop" types of functions. Another approach I've tried is to turn them on/off wholesale: Make a pair modules like contracts-on.rkt and contract-off.rkt, where the latter provides some do-nothing macros. Have your modules require a contracts.rkt, which provides all from either of the -on or -off files. This is like compiling in DEBUG vs RELEASE mode.
If you're coming from Eiffel maybe my C/C++ slant on Racket contracts won't be helpful, but I wanted to share it anyway.
精彩评论