Design by Contract in C++?
An anonymous reader asks: "I have read some of the stuff on Eiffel, watched their tutorial videos about design by contract, and the entire thing sounds like a pretty good idea. However, the problem is that we don't use Eiffel at work, and I highly doubt I could get people to come around to the idea of switching to it. Although we use a lot of C++, I can imagine that a lot of the ideas from Eiffel can be applied there. I have looked around on the net and found a few articles talking about different ways of applying design by contract using assert statements and the like. I also found the dlib C++ library on SourceForge which, among other things, puts a design by contract face on a lot of API calls. So, there are obviously people doing it. What is everyone's experience with Design by Contract in C++? What tools are there that help make it a workable system? Lastly, are there any pitfalls to taking this approach in C++?"
I call that "using interfaces" and "strict polymorphism" (and "bunnies"!!!)
...but I'm sure Java + XML is the answer.
It must be a conspiracy with the technical publishers to keep coming up with new technology fads to create a demand for new editions of old books. I stopped buying doorstoppers years ago because of this.
I have no idea what this is talking about. To wikipedia I go :)
In the development environment I work in, we use entirely C++, and combine embedded Linux, desktop Linux, and several server OSes. There are six engineers working on my part of the project (the embedded part), and a similar number working on the other parts.
Although we have enough freedom to switch over to a Design By Contract if we all agree to do it, we currently use documentation as a semi-formal contract, starting with design meetings where we verbally define the contract, which we write up piecemeal as we implement sections of code. Obviously, when multiple companies are collaborating on a business system, Design By Contract may be necessary to nail down the project requirements for each participating company. But in-house, what are the advantages of a formalized system over verbal, face-to-face communication? Wouldn't the meetings be held and the documentation be written anyway? As the project evolves, design changes can be implemented in an organized way, but again, the formal definitions would be redundant with the design change meetings.
Design by contract and invalid input.
Remember: your top-level inputs are arbitrary strings. Somebody has to be contracted for checking for buffer overflow.
I place a one line comment above each of my C++ functions that I want to have Eiffel like design by contract features:
// Note: If you don't pass reasonable values to this function I will fucking kill you
-
-
- void
- DoSomething(...)
- {
- }
PS F Ghandi
One of the proposed additions for C++0x includes Contract Programming functionality built into the core language/library.
Do a Google search for "c++ std wg" to find the working group page, which includes a list of papers and proposals.
The book The Pragmatic Programmer by Andrew Hunt and David Thomas has a chapter about Design by Contract. As it's a very good book (almost a classic) about lots of different things, I suggest you read it. Check out the reviews at Amazon, they are true.
The kind of design by contract you can get in some langauges is hard to replicate in C++. You can however get a long way, and I believe do a lot of useful work, but ASSERTing on all conditions at the start of functions, and on the return value, where approriate.
I have a lot of this kind of code in my programs and it really helps find bugs, and more importantly find them where they first appear. The big advantage of using C++ and a tiny spot of macros is that they all the ASSERTs can be removed in your final build. Actually, I have 3 level of ASSERTs, mainly categorised on how long I expect them to take, how critical the code is and if the function deals with input from the user, so some level of sanity checks are left in final builds, and there is also a debug version which doesn't take too long (if you start checking all vectors to see if they are sorted at the entry to each function, you can rapidly get very slow code).
Combination - fun iPhone puzzling
I have only every used AspectJ, not AspectC so take this with a grain of salt. AOP is basically the holy grail of design by contract. You can decide and implement powerful contracts and assertions and apply them at compile time or runtime with very little effort. They can be maintained with the code itself or as a separate aspect implemented at a higher level.
Best of all, you can use as little or as much as you want and it will not interfere with your current code.
AspectC++
LL
While it is a non-trivial thing to switch C++ compilers, Digital Mars C++ is a free (as in beer) compiler that has DBC built in as a language extension. Here is the link to the relevant documentation. http://www.digitalmars.com/ctg/contract.html One thing I think it nifty is the __invariant contract keyword. While __in and __out can be duplicated easily with #ifdefs, __invariant really has to be supported at the language level. I believe DMC++ also handles contract inheritance for class hierarchies (although I have not played with this personally).
Article: +10 (Obscure to a VFP Programmer)
History does not long entrust the care of freedom to the weak or the timid. ~Dwight D. Eisenhower
The D programming language seems to support the idea of design by contract as a standard. From the litle I know about D, the language is close enough to C++ that a switch would be easy.
0*0
00*
***
I mostly agree with you, but there's one key difference. You should never use assertions in place of input validation. You must always code as if the assertions aren't there.
BUT, and this is important, there are times when you can have a legitimate business decision to skip input validation when the cost of the checking is higher than the cost of a mistake, esp. when these are internal methods that should never get unsanitized input. In those cases you may want to have contractual assertions without a corresponding regular check. Those cases should be clearly indicated, e.g., by using a different set of assert macros.
For every complex problem there is an answer that is clear, simple, and wrong. -- H L Mencken
> -----Original Message-----
a a050601a.htm
e /message/3558
> From: James Heliotis [mailto:jeh@...]
>
> I have a student who is interested in doing a project adding
> design-by-contract assertions to another language. To my memory,
> I have never seen anything about how assertions are implemented in
> EiffelStudio, and what the challenges and pitfalls were. Can anyone
> point me to any documentation?
>
> Thanks a lot,
> James
Dear Jim:
Your student should find the following links useful:
http://www.phact.org/e/dennis4.html
http://mathworld.wolfram.com/CircleSquaring.html
http://chemistry.about.com/cs/generalchemistry/a/
Hope this helps,
-- Bertrand Meyer
http://tech.groups.yahoo.com/group/eiffel_softwar
Maybe you just want to start here.
now we need to go OSS in diesel cars
There are several options. You can simply use macros as many people do. It's clunky and tends to have issues with inheritance and documentation, but it gets the job done. Alternatively you can try the digital mars c++ compiler which supports design by contract, or if your co-workers are willing to stretch a little bit you can try the D programming language from digital mars which is very similar to C++ but offers native contracts as well as a host of other nice features. Otherwise you can go the proprietary route and get C2 which is a C++ code generator that uses comment annotations to manage contracts and is a little slicker than the macro approach.
Craft Beer Programming T-shirts
I can see it now: write contracts in a new template language, use template parameters to control run-time checking, and since it's all pure C++ (no macros), you can produce the contract documentation from the output of gccxml.
I mock, but now I really want to try it. Off to hack my own half-assed version -- Friday nights rule!
There are six engineers working on my part of the project (the embedded part), and a similar number working on the other parts.
9 is similar to 6, but they are not the same.
Vague specs are usually the problem when software projects go awry.
Having only very passing familarity with Eiffel, I'm not sure if I'm missing something, but I don't understand any significant benefit Eiffel's capabilities have over C++'s or a host of other languages with respect to design by contract.
So it has funky keywords to specify what the pre-conditions, post-conditions and invariants are, but is this really any different to putting assert() statements at the begin and end of your functions?
The obvious improvement in this area would be mathematically proving the pre-conditions, post-conditions, and invariants are always satisfied at compile time, but from the Eiffel overview of Design by Contract, it sounds like Eiffel only checks at runtime, the same way C++ does it. Is this correct? If so, what does Eiffel provide exactly that is better than C++ in this regard? Or is it just a little syntactic sugar to make the different kinds of assertions a little more clear?
"But in-house, what are the advantages of a formalized system over verbal, face-to-face communication? Wouldn't the meetings be held and the documentation be written anyway? As the project evolves, design changes can be implemented in an organized way, but again, the formal definitions would be redundant with the design change meetings."
Yea, we have meetings anyway. Let's just make every variable in the system of no specific type. Let's use them as we need them, how we need them. We can verbally agree that we'll always use ints, floats, strings, etc. No point making that compiler do any permission checking or such. Who needs provably correct code? Besides, as a project evolves, it sure sucks to change that int to a float by hand.
Oh, wait, no that'd be stupid. Why don't we have the compiler enforce compile-time and run-time checks on things? I mean beyond the fact that eStudio is ungodly evil incarnate, and Eiffel itself is overly encumbered with PASCAL/Modula-2 syntax. There is no good reason.
--
Internet Explorer (n): Another bug -- that is, a feature that can't be turned off -- in Windows.
Here's this guy working for a company that exists, apparently has cashflow, and at least has some products that are actually working and that customers are buying. So he watches this video that talks about some cool shit, and wants the other programmers at his work to switch over to this cool shit, that may be cool and may also be shit for what they're doing.
It's not just a matter of adding yet more lipstick to that pig, and it's not just a matter of using another language instead. There's an entire infrastructure of concerns that need to be coherently operative as a system. Does it need to run fast? Bye bye Ruby. Does it need to have lots of graphics? Bye bye huge numbers of academically cool and yet real world shit languages.
Forget stuff like design by contract until you've actually established that the language actually has the normal everyday boring functionality that has you yawning in boredom, but which your arse is getting fired if you don't do. Forget aspect orientated programming and all the cool shit (damn, it's cool! AND SHIT!) until you've worked out the changeover costs, the additional overhead of supporting more than one language in-house until the old uncool (but working) stuff is completely phased out.
Work out the business costs, and even more so, work out the business reasons as to why people should spend time and effort changing over vast swathes of your internal IT operations to some trendy new concept that isn't even proven past "that sounds like cool shit". Languages work and don't work for incidental reasons, rarely for specifically designed reasons. If it were purely merit, then Scheme would be what C is now.
Stop flailing around looking for some magic arse concept that will silver bullet everything - it's all shit. Nothing cool has been invented since John von Neumann threw together some cool shit and died before he got around to version two. What you see in front of you is a big pile of quickie crap thrown together in wartime without a hell of a lot of thought put into it. So it's all going to suck regardless of whatever crappy abstraction gets put over the top.
And like putting lipstick on that pig, there's a lot of money to be made making the lipstick and selling it to stupid little piggies.
in Digital Mars C++. See contracts.
while this might not be true to the spirit of 'real' dbc, it's certainly better than using assertations, because it becomes part of the interface design rather than part of the implementation: wrap parameters and return values. create a templated class that's defined by a valueT and a policyT (the policyT should be chainable if you want to check for more than one condition). make sure your class can be used as much as a valueT as you would like. most importantly, it should be able to be copy-constructed from a valueT, and in the ctor run the (possibly chained) policyT to ensure that the passed valueT holds values it likes. if it does, then just proceed. if it doesn't, then throw.
it'll look a bit cumbersome to code, but it'll ensure that the code in your function won't run if the parameters passed don't meet your conditions. similarily, a function returning such a wrapped value will throw on exit if it's post-condition isn't met.
the difference to assertations? it's part of the function's prototype, so a) code, b) highly visible (especially since it can look rather ugly) and c) gets inherited. and if it throws you can even recover from it (as opposed to the standard assert() macro).
i've started putting together a _nice_ class a few months back, but got sidetracked after a day or two. maybe i should take a look at that again, huh?
I have seen a number of articles on DBC & C++ on Artima
A quick google came up with:
http://www.artima.com/cppsource/deepspace.html
though search the Artima site and I'm sure you'll find lots more.
Another one:
http://www.ddj.com/184405997
I can't see why many people are discussing Assert to implement this function. Why not throw exceptions?
Our house chucked the single letter language long ago and it cleared up a LOT of bugs. There are too many cleaner, simpler languages to continue beating your head against that wall. My favorite is FreePascal, but Python, Rebol and Java come in a close second. Cheers!
The first thing to understand is that eiffel's design-by-contract features sound a lot nicer than they are. They could be very good, but most (all?) current compilers pretty much just translate them to a bunch of run-time precondition and postcondition assertions, which I find pretty yawn-worthy. Of course, I'm *VERY* far from an Eiffel expert, so feel free to politely correct me if the above is bunk.
I've been happy ensuring that:
- Every non-trivial object has a private invariant() method that is called at the completion of its ctor and any non-const qualified method. This helps to ensure that the object is internally consistent. It's expensive though so it's something I usually make a build-time option.
- Every method asserts its pre- and post- conditions.
- Extensive sanity checking is preformed wherever else it makes sense.
in my C++ code, and doing so has prevented more than a few bugs. That said, *nothing* is as effective in my experience as writing comprehensive unit tests that consider all the corner cases you can think of, combined with coding using safe and automatic memory management (not necessarily a gc; good use of automatic stack objects, auto_ptr, std::tr1::smart_ptr / boost::smart_ptr and other devices for tracking and managing memory ownership and allocation can be as good or better for many use cases).
--
Craig Ringer
Try the book Imperfect C++: Practical Solutions for Real-Life Programming by Matthew Wilson. I haven't read it in a while, but the first chapter is Enforcing Design: Constraints, Contracts, and Assertions. The discussion focuses largely on how to implement contracts with the template mechanism. If I recall, the technique works, but he warns that enforcement works by issuing potentially indecipherable template compile errors. That is, the technique blocks you from compiling code that breaks the contract, but the error message is so obtuse that you may spend five to ten minutes to figure out why.
I one wrote an article about that in magazine and described a schema which I used a while.
// GreaterThanZero is a class! // FieldXIsSet is a class, too! // ... your code here
First: all conditions are classs that inherit from an abstract base class that defines the methods checkPecondition and checkPostcondition, the methods do the same, just checking the condition but throwing different exceptions. (Basically you overwrite only the checkCondition method and implement the constructor to call the checkPrecondition() method.)
Example:
class BaseCondition {
public:
virtual ~ BaseCondition() { checkPostcondition(); }
virtual bool checkCondition() = 0;
virtual bool checkPrecondition() { if (!checkCondition()) throw new PreconditionViolation(this); return true; }
virtual bool checkPostcondition() { if (!checkCondition()) throw new PostconditionViolation(this); return true; }
}
Second:
you make some macros, like ensure(x) and require(x), invariant(x). The code of those is simple, I ommit it here. They all only allocate an object of the given class on the stack, require calls checkPrecondition(); ensure does nothing but waits for the stack unwinding so the destructor of the condition is called which performs the post condition check. Invariant(x) does both.
Problems are like some people said: oring preconditions and anding post conditions needs to be done manually.
Invariants are a problem if your method calls other methods with pre/post conditions
Biggest problem:
You use this only in the implementation of your code like:
void myMethod(int a) {
require(GreaterZero(a));
ensure((FieldXIsSet(this));
}
So, you wont see the contract in your header files unless you put the production code into its own methods and wrap it in the header files accordingly.
Advantage: as all conditions are classes they can freely be reused and combined.
Biggest disadvantage: the compiler knows nothing about all that, unless like in Eiffel where the compiler would reject calls and flag them as error where it can statically descided.
angel'o'sphere
P.S. oops, I see now it was more complicated to implement. The macros instanciated a template class with the Condition class as argument, and called the pre/post condition checks. That means you don't have to do complicated constructor and destructor implementatison but only have to have a class as condition with a defined method whcih can be callled from a template. Mail me if you need it concrete, I think I can dig that stuff out from an old computer.
Cost free eBook I read (by iBook/Kobo/Amazon/ObookO/Gutenberg etc.): "The Green Odyssey" by Philip Jose Farmer.
I'm sure some future version of Java will proudly proclaim the "breakthrough" of supporting contracts. In the same way they made a big deal of finally implementing generics.
Eiffel: proof that the best technology doesn't always win.
First off, I wrote a little paper on it at the time.
I implemented it with macros. The main issues were:- It required a funny return macro, to guarantee exiting through the postconditions
- Compilers started to complain about gotos crossing over my variable declarations. (I tried to put pre and post conditions at the top of the function, jump past the postconditions, and then on return jump back to the postconditions to execute them. This approach had serious issues, and would force me to declare some variables higher up.)
Despite the admitted problems, it was a radically successful effort, eliminating a whole class of bugs for me--most importantly in the area of attempted reuse of classes where I saved tons of debugging time. (Like the time I attempted to reuse a dictionary class, not realizing that my dictionary did not accept certain types of keys, or the time I found out with the same class that I was generating negative hashcodes.) It never ceases to amaze me how some of the world's most important programming constructs--particulary for correctness--have not made it into mainstream languages.dynamic/static is what you mean. Try some reading:
http://en.wikipedia.org/wiki/Type_system#Types_ofOf corse C++ adcocates change the C++ entry to there liking faster then you can corect it but as far as I see it a language which allows:
is not strongly typed. In fact and just for good measure:
The printout is neither an exeption dump nor a -1 so C++ is weakly typed.
Martin
The mistake you are making (and you are not alone here) is to assume that strongly impies static. But that is not true - the typing system is 4 dimensional:
static/dynamic: Can a variable change type?
strong/weak: Are types converted implicidly?
safe/unsafe: Are data convertions save? This includes dangling pointers!
nominative/structural: Are types bound to the a more or to the structure?
Some combinations are more common then other but in theory any combination is possible. And quite often a language us not 100% one or the other.
Martin
That's exactly the point.
The current Eiffel compilers essentially convert pre- and post- condition sections to assertions. Faults are not detected until runtime when that code is excersised. A comprehensive test suite with full code coverage is necessary.
In other words, they don't do anything better than assertions used according to suitable conventions - except look prettier.
I'm not sure what you're getting at with respect to "a million cryptic asserts all over the place (which will perforce be bound to your implementation rather than the point of contracts which is that they bind to the interface)" - in that assertions used as interface contact checking will be present only at interface entry and exit points (like contract blocks) and no more cryptic than contract block entries, which they're logically equivalent to. I'd _prefer_ them in contract blocks, but with something as simple as a standard comment to deliniate where they begin and end it's not a big issue.
Now, if Eiffel compilers started doing some static analysis to validate interfaces at compile time then I might care, because there's something I can benefit from that I _can't_ get from well used and documented assertions. The advantage of using contract blocks might be that while Eiffel compilers can't do this now, theoretically they might in the future. On the other hand, I'd have to endure a more limited set of available libraries, the irritation of talking to C++ code via C adapter interfaces, and quite a bit more besides for a benefit that may never arrive.
I'll stick with my test suite (which I'll need anyway) and careful documented use of assertions to check the interface behaviour, I think.
--
Craig Ringer