Jump to page: 1 2
Thread overview
Pre / Post / Invariant Best Practices
Jul 09, 2004
David Barrett
Jul 09, 2004
Walter
Jul 09, 2004
David Barrett
Jul 09, 2004
Walter
Jul 09, 2004
Arcane Jill
Jul 09, 2004
Walter
Jul 10, 2004
Derek
Wiki? [Slightly OT] (was Pre / Post / Invariant...)
Jul 10, 2004
Arcane Jill
Jul 10, 2004
Andy Friesen
Jul 09, 2004
David Barrett
Jul 10, 2004
Norbert Nemec
Jul 09, 2004
Bent Rasmussen
Jul 10, 2004
Norbert Nemec
Jul 12, 2004
Walter
July 09, 2004
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


July 09, 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?
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?

Consider a function that sorts its input. A postcondition would test to see if the data is really sorted.


July 09, 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...
> > 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?
>
> Consider a function that sorts its input. A postcondition would test to
see
> if 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


July 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



July 09, 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.


July 09, 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!


July 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 -
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.

Rock on, Jill! You've got it exactly right. Can I encourage you to post this in the D wiki?


July 09, 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...
> >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.

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.

> >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.

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.

> >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).

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


July 10, 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...
>> 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.
> 
> Rock on, Jill! You've got it exactly right. Can I encourage you to post this in the D wiki?

Agreed. This is spot on, Jill. And very nicely said too.

-- 
Derek
Melbourne, Australia
July 10, 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


« First   ‹ Prev
1 2