digitalmars.D - Pre / Post / Invariant Best Practices
- David Barrett (33/33) Jul 08 2004 I'm trying to wrap my head around how best to use these.
- Walter (6/11) Jul 08 2004 I
- David Barrett (14/25) Jul 08 2004 writing/maintaining
- Walter (5/7) Jul 09 2004 Not much right now. But I expect as people get more into D, they'll use ...
- Arcane Jill (44/65) Jul 09 2004 Curiously, the way I use them is completely different from that in which...
- Walter (14/29) Jul 09 2004 because
- Derek (5/37) Jul 09 2004 Agreed. This is spot on, Jill. And very nicely said too.
- Arcane Jill (23/25) Jul 09 2004 I don't know how. I headed over to Wiki4D to make the attempt, but got l...
- Andy Friesen (15/23) Jul 10 2004 A website that anybody can edit, basically. The first one is the
- David Barrett (28/45) Jul 09 2004 because
- Norbert Nemec (5/13) Jul 10 2004 It is more than that. For finding your own bugs, a plain assert would be
- Bent Rasmussen (17/17) Jul 09 2004 To my knowledge Design by Contract is an Eiffel concept by origin. If yo...
- Norbert Nemec (21/22) Jul 10 2004 It is design-by-contract: Both, pre- and post-conditions are part of the
- Walter (9/13) Jul 11 2004 coding
I'm trying to wrap my head around how best to use these. Preconditions I get: Validate every input to my methods because I can't trust the caller. Likewise, validate that the object is in an acceptable state *for this method*. (Different methods might have different "valid" states: File.open() asserts that the file is closed, while File.close() asserts that it's open.) Invariants I kinda get: Validate that the object is in one of the many possible valid states. This doesn't eliminate validating the specific state in the Precondition, but it can simplify the Precondition. (For example, if File.filename must be set whenever it's open, then assert this relationship in the invariant. Then you don't need to test both the filename and the open state in the File.open() and File.close() Precondition -- testing one is sufficient to prove the other.) But Postconditions elude me: It seems of very low value for a method to test its own output: that's like the fox guarding the henhouse. If I'm going to have a test, I'd prefer that the caller do the testing to verify the method output what it expected. Just like a method can't trust its input and needs to validate it with preconditions, it can't trust a return value and thus must validate it, too. After all, the return value might be "valid" from the perspective of the method, but "invalid" from the perspective of the caller. Granted, I can see the value of periodically asserting your state while within some complex operation. But by the time I get to actually returning a value, I should have a pretty high degree of confidence that I'm returning the right value. And if I'm just doing a final check to verify the object is still sound, that should be done in a class invariant, no? So my question is: what "best practices" have you been using in reality? I personally use Preconditions and copious amounts of asserts. But Invariants and Postconditions don't seem to offer real-world value to the code I'm writing. Am I missing something? Do others find that writing/maintaining Invariants and Postconditions pays for themselves in the bugs they avoid? -david
Jul 08 2004
"David Barrett" <dbarrett quinthar.com> wrote in message news:cckop5$c8g$1 digitaldaemon.com...So my question is: what "best practices" have you been using in reality?Ipersonally use Preconditions and copious amounts of asserts. ButInvariantsand Postconditions don't seem to offer real-world value to the code I'm writing. Am I missing something? Do others find that writing/maintaining Invariants and Postconditions pays for themselves in the bugs they avoid?Consider a function that sorts its input. A postcondition would test to see if the data is really sorted.
Jul 08 2004
"Walter" <newshound digitalmars.com> wrote in message news:cckuq3$kab$1 digitaldaemon.com..."David Barrett" <dbarrett quinthar.com> wrote in message news:cckop5$c8g$1 digitaldaemon.com...writing/maintainingSo my question is: what "best practices" have you been using in reality?Ipersonally use Preconditions and copious amounts of asserts. ButInvariantsand Postconditions don't seem to offer real-world value to the code I'm writing. Am I missing something? Do others find thatavoid?Invariants and Postconditions pays for themselves in the bugs theyConsider a function that sorts its input. A postcondition would test toseeif the data is really sorted.I agree that there are times a Postcondition *could* be used, and that's a good example. But I'm not disputing it's theoretical value. Rather, I'm asking asking: How often do people really use them *in practice*? Would you say that "none", "some", "most", or "all" D functions you write use Postconditions? As a comparison, do you use "fewer", "as many", or "more" Postconditions as Preconditions? -david
Jul 08 2004
"David Barrett" <dbarrett quinthar.com> wrote in message news:ccl7qu$1216$1 digitaldaemon.com...But I'm not disputing it's theoretical value. Rather, I'm asking asking: How often do people really use them *in practice*?Not much right now. But I expect as people get more into D, they'll use them more. For example, look at std.format.doFormat() - it's full of nested functions!
Jul 09 2004
In article <cckop5$c8g$1 digitaldaemon.com>, David Barrett says...I'm trying to wrap my head around how best to use these.Curiously, the way I use them is completely different from that in which you use them. Could be the start of an interesting discussion...Preconditions I get: Validate every input to my methods because I can't trust the caller.Oh contraire! You shouldn't use preconditions to validate USER input - because those "in" blocks will disappear altogether in a release build. You'll end up with code that only works in a debug build. Preconditions should never result in different behavior between release and debug builds. Besides which, what use is an assert message to an end-user? No, preconditions exist to help YOU find YOUR bugs. The way I use it, if the input is dependant upon user-input, then I should test for validity in the function body, not the precondition, and throw an exception or otherwise handle it if it turns out to be nonsense. The in-block is there to test whether or not my own code contains bugs. In simple terms, the in-block asserts that the input is what I *EXPECT* it to be. (And in the case of user-input, I expect it to sometimes be rubbish, and hence consider rubbish to be legal input). In this paradigm, every assert failure within an in-block represents one bug found in another part of code ... which then gives me the power to go and fix it.Likewise, validate that the object is in an acceptable state *for this method*. (Different methods might have different "valid" states: File.open() asserts that the file is closed, while File.close() asserts that it's open.)I don't think it should be an error to close a file twice. The second close should be silently ignored, and should be completely harmless. And writing to a file which is not open should surely throw a WriteError? Again, I remind you that asserts - along with in-blocks and out-blocks - will not be present in a release build. What's your program gonna do then? Crash?Invariants I kinda get:They're pretty easy to understand, in that they can only really be used for bug-finding.But Postconditions elude me: It seems of very low value for a method to test its own output: that's like the fox guarding the henhouse.Really? I find postconditions most useful of all. In the Int class (etc.bigint.bigint) they're used all the time. For example - there's a function which, given input x, returns the integer square root y of x, and the remainder r. The postcondition asserts that (y*y+r == x). In other words, the postcondition will tell me if the function contains a bug. Simply calling the function a few times without seeing an assert gives me high confidence that the function is okay.After all, the return value might be "valid" from the perspective of the method, but "invalid" from the perspective of the caller.There is no "valid" or "invalid". Just "bug-free" or "not bug-free". That's what you're testing for.And if I'm just doing a final check to verify the object is still sound, that should be done in a class invariant, no?Yes it should. But that wouldn't have helped me with the square root example, would it? Postconditions serve a different purpose.So my question is: what "best practices" have you been using in reality? I personally use Preconditions and copious amounts of asserts. But Invariants and Postconditions don't seem to offer real-world value to the code I'm writing.They offer value to the person WRITING the code, not value to the person USING the code.Am I missing something?You may possibly be missing the fact that all of these things will disappear into the ether in a release build. Never assume that an end user will have the benefit of these things in your code.Do others find that writing/maintaining Invariants and Postconditions pays for themselves in the bugs they avoid?Yes, but they don't AVOID bugs - they FIND bugs. Your end-users avoid them, because /you/ fix them before those other people even see them. Arcane Jill
Jul 09 2004
"Arcane Jill" <Arcane_member pathlink.com> wrote in message news:cclgul$1g20$1 digitaldaemon.com...Oh contraire! You shouldn't use preconditions to validate USER input -becausethose "in" blocks will disappear altogether in a release build. You'll endupwith code that only works in a debug build. Preconditions should neverresult indifferent behavior between release and debug builds. Besides which, whatuse isan assert message to an end-user? No, preconditions exist to help YOU find YOUR bugs. The way I use it, iftheinput is dependant upon user-input, then I should test for validity in the function body, not the precondition, and throw an exception or otherwisehandleit if it turns out to be nonsense. The in-block is there to test whetheror notmy own code contains bugs. In simple terms, the in-block asserts that the input is what I *EXPECT* ittobe. (And in the case of user-input, I expect it to sometimes be rubbish,andhence consider rubbish to be legal input). In this paradigm, every assert failure within an in-block represents one bug found in another part ofcode ...which then gives me the power to go and fix it.Rock on, Jill! You've got it exactly right. Can I encourage you to post this in the D wiki?
Jul 09 2004
On Fri, 9 Jul 2004 09:30:43 -0700, Walter wrote:"Arcane Jill" <Arcane_member pathlink.com> wrote in message news:cclgul$1g20$1 digitaldaemon.com...Agreed. This is spot on, Jill. And very nicely said too. -- Derek Melbourne, AustraliaOh contraire! You shouldn't use preconditions to validate USER input -becausethose "in" blocks will disappear altogether in a release build. You'll endupwith code that only works in a debug build. Preconditions should neverresult indifferent behavior between release and debug builds. Besides which, whatuse isan assert message to an end-user? No, preconditions exist to help YOU find YOUR bugs. The way I use it, iftheinput is dependant upon user-input, then I should test for validity in the function body, not the precondition, and throw an exception or otherwisehandleit if it turns out to be nonsense. The in-block is there to test whetheror notmy own code contains bugs. In simple terms, the in-block asserts that the input is what I *EXPECT* ittobe. (And in the case of user-input, I expect it to sometimes be rubbish,andhence consider rubbish to be legal input). In this paradigm, every assert failure within an in-block represents one bug found in another part ofcode ...which then gives me the power to go and fix it.Rock on, Jill! You've got it exactly right. Can I encourage you to post this in the D wiki?
Jul 09 2004
In article <ccmhl2$30jv$2 digitaldaemon.com>, Walter says...Rock on, Jill! You've got it exactly right. Can I encourage you to post this in the D wiki?I don't know how. I headed over to Wiki4D to make the attempt, but got lost and confused. To be honest, until someone said "Let's start a Wiki for D" I thought Wiki was a free encyclopedia (although I see now that's actually called Wikipedia). It looks like there's no connection between the two. So, since my knowledge appears to be very deficient in some areas, perhaps someone can enlighten me. 1) What the hell is a Wiki? 2) Why is it called "wiki"? 3) How do you add pages to it, edit it, etc? 4) What's to stop spammers and site-vandals from doing (3)? 5) If I click on Edit, I see a plain text entry box in some weird non-HTML format I don't understand. What format is this? 6) Is there a tutorial somewhere on the web that explains all this for us Wiki-newbies? 7) What is the connection between this use of the word "wiki" and the wikipedia (if any). In short, I can't put that previous post in the Wiki. I tried, and gave up in confusion. But I give permission for someone else to post my words if they so desire. Long term - obviously the Wiki thing looks useful, so someone would care to enlighten me I promise I'll try to bring my skills up to date. Arcane Jill
Jul 09 2004
Arcane Jill wrote:[...] perhaps someone can enlighten me. 1) What the hell is a Wiki?A website that anybody can edit, basically. The first one is the Portland Pattern Repository, which can be found at <http://c2.com/cgi/wiki> (incidently, there's loads and loads of awesome stuff buried in there. it's not hard to dive in and come back out with gray hair)2) Why is it called "wiki"?<http://c2.com/cgi/wiki?EtymologyOfWiki>3) How do you add pages to it, edit it, etc? 4) What's to stop spammers and site-vandals from doing (3)?The biggest reason WhyNobodyDeletesWiki <http://c2.com/cgi/wiki?WhyNobodyDeletesWiki> is because it's so very easy to undo. Every wiki I know of stores changes made in the last few weeks or so, so anybody at all can undo it, and there are generally quite a lot more people interested in fixing it than breaking it. :)5) If I click on Edit, I see a plain text entry box in some weird non-HTML format I don't understand. What format is this?Wikis have their own FormattingRules <http://c2.com/cgi/wiki?TextFormattingRules> Anyway, I'm sure you get the idea. It really is as simple as it sounds. :) -- andy
Jul 10 2004
"Arcane Jill" <Arcane_member pathlink.com> wrote in message news:cclgul$1g20$1 digitaldaemon.com...In article <cckop5$c8g$1 digitaldaemon.com>, David Barrett says...becausePreconditions I get: Validate every input to my methods because I can't trust the caller.Oh contraire! You shouldn't use preconditions to validate USER input -those "in" blocks will disappear altogether in a release build.Sorry! I didn't mean to imply otherwise. I agree, user input requires it's own type of validation. I meant to state that a precondition validates a method's input *arguments*, not user input. Preconditions, Postconditions, and Invariants are tools to pre-emptively identify bugs in close proximity to the source. I think we agree on this point.File.open()Likewise, validate that the object is in an acceptable state *for this method*. (Different methods might have different "valid" states:open.)asserts that the file is closed, while File.close() asserts that it'sI don't think it should be an error to close a file twice. The secondcloseshould be silently ignored, and should be completely harmless.That's an interesting argument in itself (I take a very strict approach using the same logic as the D compiler having no warnings). But that's outside the scope of my question.likeBut Postconditions elude me: It seems of very low value for a method to test its own output: that'sfunctionthe fox guarding the henhouse.Really? I find postconditions most useful of all. In the Int class (etc.bigint.bigint) they're used all the time. For example - there's awhich, given input x, returns the integer square root y of x, and theremainderr. The postcondition asserts that (y*y+r == x).Ah, thanks. This helps me. I guess Postconditions -- like anything -- are an art. Looking over bigint_int.d helps me see that. I can see that functions whose primary value is to produce output benefit most from Postconditions. But I guess I had in mind things like Sockets (how can I confirm the data was sent?) or complex algorithms (how can I verify an XML document was properly parsed?). Of course, big functions are composed of small functions, and each of those might have its own Postconditions. Thanks for walking me through this; still trying to figure out how to properly place D in the pantheon of tools at hand. -david
Jul 09 2004
Arcane Jill wrote:It is more than that. For finding your own bugs, a plain assert would be good enough. The post-condition is more like a promise to the outside world. You are telling publicly: this function will do that. Better than any comment: the promise can even be checked.But Postconditions elude me: It seems of very low value for a method to test its own output: that's like the fox guarding the henhouse.Really? I find postconditions most useful of all. In the Int class (etc.bigint.bigint) they're used all the time. For example - there's a function which, given input x, returns the integer square root y of x, and the remainder r. The postcondition asserts that (y*y+r == x).
Jul 10 2004
To my knowledge Design by Contract is an Eiffel concept by origin. If you want to see powerful use of contracts you should check out the Eiffel structures library. A powerful aspect of pre- and postconditions is that they can be inherited. Since in Eiffel you cannot assign a value to a field from outside the object, you will need to make a set method to do this. So you make a setter. Next someone inherits from your class, redefines the setter, adds event hanling, but forgets to set the actual value. The postcondition will be inherited and the contract breach will manifest at runtime. This example, although trivial, shows that even in the simplest of cases, a postcondition is relevant. I'm not so sure it isn't an error (Arcane Jill thinks not), to close a file twice. It is an error in that it isn't possible to close a closed file, no transition takes place, however the outcome is acceptable. So it is an error without negative consequence other than bloat or (remotely possible) an uncorrected misunderstanding of the semantics of close (I can see it now: But the file was only half-way closed!) Whether bloat like this should be avoided through contracts is a matter of taste.
Jul 09 2004
David Barrett wrote:But Postconditions elude me:It is design-by-contract: Both, pre- and post-conditions are part of the *interface*. There are several aspects to that fact. In D, there seems to be very little distinction between interface and implementation, both being coded in the same file. I believe, though, that it is possible to extract the interface of a given module, using the compiler. In that case, the pre- and post-conditions should be put into the interface as well. They document how a function is to be used, and what it produces. It is understood, that pre- and postconditions should only ever depend on public functions and the function arguments. One important aspect of pre- and post-conditions is, that they are inherited along with the interface. (The the chapter "contracts") An overriding function must keep the contract of the original. It my loosen the in-contract or tighten the out-contract. Plain asserts in the body, on the other hand, have nothing to do with contracts, but are merely a kind of "checked documentation", helping in understanding the implementation code correctly. Whether design-by-contract helps you in avoiding bugs depends on your coding style. It certainly is only interesting for libraries and larger projects that define clear interfaces between individual parts. For small projects, thinking about clear interfaces often is more effort than it is worth.
Jul 10 2004
"Norbert Nemec" <Norbert.Nemec gmx.de> wrote in message news:cco50m$27n6$1 digitaldaemon.com...Whether design-by-contract helps you in avoiding bugs depends on yourcodingstyle. It certainly is only interesting for libraries and larger projects that define clear interfaces between individual parts. For small projects, thinking about clear interfaces often is more effort than it is worth.True enough. One aspect of D that sometimes is controversial is I wanted to make it easy to write quick-and-dirty programs as well as provide the scaffolding for large, complex projects. That's why, for example, 'public' is the default access rule for class members, and object.d is implicitly imported. DbC is a waste of effort for Q&D programs, which is why it is optional.
Jul 11 2004