www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Good Contract programming idiom?

reply bearophile <bearophileHUGS lycos.com> writes:
This is currently present in this Wikipedia page:
http://en.wikipedia.org/wiki/Class_invariant#D

It shows a normal way to use contract programming in D:

class Date {
    private int day, hour;
 
    invariant() {
        assert(1 <= day && day <= 31);
        assert(0 <= hour && hour < 24);
    }
 
    this(int d, int h) //constructor
        in {
            assert(1 <= d && d <= 31);
            assert(0 <= h && h < 24);
        }
        out {
            assert(day == d);
            assert(hour == h);
        }
        body {
            day = d;
            hour = h;
        }
 
    public void setDay(int d)
        in { assert(1 <= d && d <= 31); }
        out { assert(day == d); }
        body {
            day = d;
        }
 
    public void setHour(int h)
        in { assert(0 <= h && h < 24); }
        out { assert(hour == h); }
        body {
            hour = h;
        }
}


But generally public functions must test arguments in release mode too, so I
(and lot of other people) don't like to use asserts in this situation. It's
better to use an always present test followed by a throw (so such test is not
in the precondition).

So this is the code that I prefer:

/// Thrown when an illegal argument is encountered.
class IllegalArgumentException : Exception {
    this(string msg) {
        super(msg);
    }
}
 
 
class Date {
    private int day, hour;
 
    invariant() {
        assert(1 <= day && day <= 31);
        assert(0 <= hour && hour < 24);
    }
 
    this(int d, int h) //constructor
        out {
            assert(day == d);
            assert(hour == h);
        }
        body {
            if (d < 1 || d > 31)
                throw new IllegalArgumentException("Wrong day.");
            if (h < 0 || h >= 24)
                throw new IllegalArgumentException("Wrong hour.");
 
            day = d;
            hour = h;
        }
 
    public void setDay(int d)
        out { assert(day == d); }
        body {
            if (d < 1 || d > 31)
                throw new IllegalArgumentException("Wrong day.");
            day = d;
        }
 
    public void setHour(int h)
        out { assert(hour == h); }
        body {
            if (h < 0 || h >= 24)
                throw new IllegalArgumentException("Wrong hour.");
            hour = h;
        }
}
 
 
void main() {
    Date d = new Date(/*d=*/10, /*h=*/5);
    d.setHour(30); // throws
}

What do you think? Do you agree that's better to use exceptions like this to
test arguments in public methods (instead of using asserts in preconditions)?

I have had to define locally that IllegalArgumentException because I think it's
missing still in Phobos2 core.exception.
Those /*d=*/   /*h=*/  are useful because D doesn't support named arguments yet.

Bye,
bearophile
Mar 02 2010
next sibling parent reply Norbert Nemec <Norbert Nemec-online.de> writes:
bearophile wrote:
 But generally public functions must test arguments in release mode too, so I
(and lot of other people) don't like to use asserts in this situation. It's
better to use an always present test followed by a throw (so such test is not
in the precondition).
For this statement, you should make a distinction between libraries and applications. Indeed, contracts are part of the interface, so a released library should still allow to check for them. Breach of a contract, however, is always a bug. In a correct program, user interaction should never break either contracts or assertions. If you trust your code enough to drop the assertions, you can just as well drop the contracts. The correct way to handled contracts for libraries would actually be to store them as part of the library interface information. A release-mode library would then contain neither assertions nor contracts, but leave it to the compiler to add contract-checks for calls to the library, when compiling an application in devel-mode.
Mar 02 2010
parent reply Fawzi Mohamed <fawzi gmx.ch> writes:
On 2-mar-10, at 15:50, Norbert Nemec wrote:

 bearophile wrote:
 But generally public functions must test arguments in release mode  
 too, so I (and lot of other people) don't like to use asserts in  
 this situation. It's better to use an always present test followed  
 by a throw (so such test is not in the precondition).
For this statement, you should make a distinction between libraries and applications. Indeed, contracts are part of the interface, so a released library should still allow to check for them. Breach of a contract, however, is always a bug. In a correct program, user interaction should never break either contracts or assertions. If you trust your code enough to drop the assertions, you can just as well drop the contracts. The correct way to handled contracts for libraries would actually be to store them as part of the library interface information. A release-mode library would then contain neither assertions nor contracts, but leave it to the compiler to add contract-checks for calls to the library, when compiling an application in devel-mode.
well there are checks that I want to keep also in deployment, for example if they check stuff that depends on user input. Yes and if (!x) throw ...; is the correct way to handle this, but sometime for stupid checks I would like to use the compactness of assert, I already thought that having a aassert (always assert) would be nice...
Mar 02 2010
next sibling parent Norbert Nemec <Norbert Nemec-online.de> writes:
Fawzi Mohamed wrote:
 
 On 2-mar-10, at 15:50, Norbert Nemec wrote:
 
 bearophile wrote:
 But generally public functions must test arguments in release mode 
 too, so I (and lot of other people) don't like to use asserts in this 
 situation. It's better to use an always present test followed by a 
 throw (so such test is not in the precondition).
For this statement, you should make a distinction between libraries and applications. Indeed, contracts are part of the interface, so a released library should still allow to check for them. Breach of a contract, however, is always a bug. In a correct program, user interaction should never break either contracts or assertions. If you trust your code enough to drop the assertions, you can just as well drop the contracts. The correct way to handled contracts for libraries would actually be to store them as part of the library interface information. A release-mode library would then contain neither assertions nor contracts, but leave it to the compiler to add contract-checks for calls to the library, when compiling an application in devel-mode.
well there are checks that I want to keep also in deployment, for example if they check stuff that depends on user input. Yes and if (!x) throw ...; is the correct way to handle this, but sometime for stupid checks I would like to use the compactness of assert, I already thought that having a aassert (always assert) would be nice...
That strategy is fine for quick-and-dirty code, but for any code that you actually want to allow others to use, it is not a good idea. Since the terms "quick-and-dirty" and "deployment" are mutually exclusive, there should not be a problem here... If you want simple checks for user input, just define a routine yourself, but don't call it 'assert'. If you want to be really helpful to the user, let this routine write "You did something wrong!" to avoid being blamed for a bug. (Whenever I encounter a assertion failure in a program that I use, I silently assume that it is a bug.)
Mar 02 2010
prev sibling parent reply dsimcha <dsimcha yahoo.com> writes:
== Quote from Fawzi Mohamed (fawzi gmx.ch)'s article
 I already thought that having a aassert (always assert) would
 be nice...
In D2, isn't that what enforce() is for?
Mar 02 2010
parent "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
dsimcha wrote:
 == Quote from Fawzi Mohamed (fawzi gmx.ch)'s article
 I already thought that having a aassert (always assert) would
 be nice...
In D2, isn't that what enforce() is for?
It is indeed. I've found enforce() to be extremely practical. I use it every time I would otherwise write if (some test fails) throw new Exception("Some test failed"); Besides being slightly shorter than the above, it saves me the trouble of providing the file and line number where the error occurred. Also, its sibling errnoEnforce() is invaluable when working directly with C functions, where the alternative is if (some test fails) throw new Exception(to!string(strerror(errno))); In fact, there are a lot of goodies in std.contracts that I suspect most people aren't aware of. -Lars
Mar 02 2010
prev sibling next sibling parent Lutger <lutger.blijdestijn gmail.com> writes:
Theoretically exceptions are situations you expect can happen, even though 
the code is bug free, while assertions always indicate a bug. 

I think the main implication of this is that assertions should behave 
differently. They should halt the program at once so the developer's 
attention is forced upon the bug, even though the bug may be recoverable.  
Furthermore, your development version of your software can run very slow, 
it's usually no problem. With easy way to compile out assertions, you are 
more inclined to use them liberally. Or to put it the other way: you are 
likely to implement less checking if it comes at a cost for your release 
build. 

Then there is the case where you want to leave some 'assertion checks' in 
release mode too, like you mention. Ideally you may want something that 
throws AssertError when compiled in debug mode and InvalidArgumentException 
in release mode. I think that whenever code is important enough to have such 
extensive checking, it is a good idea to do something like this.
Mar 02 2010
prev sibling next sibling parent reply Michiel Helvensteijn <m.helvensteijn.remove gmail.com> writes:
bearophile wrote:

 What do you think? Do you agree that's better to use exceptions like this
 to test arguments in public methods (instead of using asserts in
 preconditions)?
Short answer: No! Longer answer: It depends. With exceptions, your methods and constructors basically double as a test of input validity. You can catch the exception and recover. And if this is part of the behavioral specification, that's fine. But I suspect these exceptions are not supposed to be caught, and are only used as makeshift release mode assertions. That's not nice. Preconditions are part of the public interface, and D should treat them better. Even in release mode, I'd want to keep the runtime checks, except if we have static proof of total correctness at every call site, in which case runtime checks are redundant. If the programmer is deadset on removing runtime checks for unproven assertions, he should have to compile with the --dangerous-unchecked-assertions flag. -- Michiel Helvensteijn
Mar 02 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
dsimcha:

In D2, isn't that what enforce() is for?<
You are probably right :-) Have Andrei design part of the standard library is not enough, I also have to understand why the idioms it encourages are good :-) Now I have understood what enforce is useful for (as a shortcut for a test+throw), but I prefer enforceEx() that allows me to choose the right exception too. Reading the whole source code of Phobos is not enough, I don't uderstand still why and where std.contracts.pointsTo and std.contracts.assumeSorted can be useful. AssumeSorted() can even leave a "sorted" bit set somewhere inside the array. std.contracts.assumeUnique is not integrated with the type system, so it less useful. ---------------------- Lutger:
Theoretically exceptions are situations you expect can happen, even though the
code is bug free, while assertions always indicate a bug.<
OK.
your development version of your software can run very slow, it's usually no
problem. With easy way to compile out assertions, you are more inclined to use
them liberally.<
D has debug levels too, so you can put more costly tests at a layer 2 and all the other tests at the layer 1. So most debug builds can be fast enough.
Then there is the case where you want to leave some 'assertion checks' in
release mode too, like you mention. Ideally you may want something that throws
AssertError when compiled in debug mode and InvalidArgumentException in release
mode.<
This can be done just keeping asserts in the precondition, and putting the exceptions in the body (if you are a really tidy person you can even disable the exceptions in not release built). But in practice I think the "good enough" thing to do is to be sure essential precontions are met, and stop the code otherwise. ------------------ Michiel Helvensteijn:
But I suspect these exceptions are not supposed to be caught, and are only used
as makeshift release mode assertions.<
You are probably right. enforce() or enforceEx() are probably meant to become the idiomatic way to write such asserts that acts as exceptions. Maybe they can be replaced by special future asserts that can't be disabled :-)
That's not nice. Preconditions are part of the public interface, and D should
treat them better. Even in release mode, I'd want to keep the runtime checks,
except if we have static proof of total correctness at every call site, in
which case runtime checks are redundant. If the programmer is deadset on
removing runtime checks for unproven assertions, he should have to compile with
the --dangerous-unchecked-assertions flag.<
Current D compilers generally don't remove asserts statically thanks to proofs. Future D compilers can learn to do this better (and at that point I agree that removing the preconditions from the code as in that Wikipedia page will be bad). I think most D programmers today want to remove runtime checks for unproven assertions, that's the point of the -release compile flag. SafeD modules can keep the asserts. With the LDC compiler you have a finer control of what tests to disable (only contracts, nornal asserts, array bounds, etc). With the current DMD compiler and current usages of D I think what's written in that Wikipedia page is better. Thank you for all the answers, bye, bearophile
Mar 02 2010
next sibling parent reply Kagamin <spam here.lot> writes:
bearophile Wrote:
 I think most D programmers today want to remove runtime checks for unproven
assertions, that's the point of the -release compile flag.
Never deemed -release flag as a useful thing, may be I just don't put in useless asserts? And I don't think that detailed exceptions do a lot more than simple asserts. Job is done faster with simple assert and I don't see much difference between IllegalArgumentException: wrong day and day>=1 && day<=31 assertion failed Though the former may create better image for your library.
Mar 02 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Kagamin:

 Never deemed -release flag as a useful thing, may be I just don't put in
useless asserts?
-release disables array bounds tests too. This can produce D code 2-3 times faster if you process array a lot, because DMD is not (as recent versions of Java HotSpot) able to infer many situations where it can remove them. Future D compilers able to do what HotSpot does, will have less need of -release mode. (With LDC you can disable just array bound tests and keep asserts, if you want).
 And I don't think that detailed exceptions do a lot more than simple asserts.
Job is done faster with simple assert and I don't see much difference between
 IllegalArgumentException: wrong day
 and
 day>=1 && day<=31 assertion failed
 Though the former may create better image for your library.
That was a silly and very simple example, where there's no real need of an error message. But there are many situations where giving a better error message is very useful, because it can become quite less easy to understand why an assert has failed and why testing such assert in this part of code is important to assure the correct successive operations done by the code. Note that D asserts/enforces have an optional string for error message, just like exceptions :-) I have modified a little the second D version, using enforce() and I have improved the text that explains this comes from practical considerations (while I think in theory right Michiel Helvensteijn is right): http://en.wikipedia.org/wiki/Class_invariant#D Bye, bearophile
Mar 02 2010
parent Kagamin <spam here.lot> writes:
bearophile Wrote:

 -release disables array bounds tests too.
 
I've hit an array bounds error which was os-dependent. That was fearsome.
Mar 03 2010
prev sibling parent Lutger <lutger.blijdestijn gmail.com> writes:
bearophile wrote:

 This can be done just keeping asserts in the precondition, and putting the
 exceptions in the body (if you are a really tidy person you can even
 disable the exceptions in not release built). But in practice I think the
 "good enough" thing to do is to be sure essential precontions are met, and
 stop the code otherwise.
The problem is this: in release mode you may be able to recover. The Date function may be part of a not so fundamental part of the application, or there is an alternative code path that can be tried. If you replace your asserts with exceptions that are then caught and recovered from, it becomes much harder to debug during development than is necessary. In this case you simply do not know, for these decisions are made probably on a higher level than a Date class.
Mar 02 2010
prev sibling parent reply Lionello Lunesu <lio lunesu.remove.com> writes:
On 2-3-2010 20:44, bearophile wrote:
 What do you think? Do you agree that's better to use exceptions like this to
test arguments in public methods (instead of using asserts in preconditions)?
I agree with you. I also prefer exceptions for illegal argument values. I test them with asserts only in private methods. L.
Mar 03 2010
parent reply Norbert Nemec <Norbert Nemec-online.de> writes:
Lionello Lunesu wrote:
 On 2-3-2010 20:44, bearophile wrote:
 What do you think? Do you agree that's better to use exceptions like this to
test arguments in public methods (instead of using asserts in preconditions)?
I agree with you. I also prefer exceptions for illegal argument values. I test them with asserts only in private methods.
No! No! No! Design-by-contract means that it is the application's duty to make sure that argument values are correct. If the program is correct, the library can trust that the argument values are correct and does not need to do checks. This is exactly the same situation that assertions are for: Double-checking something to catch potential bugs. Exceptions are a very different issue and should never be used for this purpose. A library interface simply is something different than a user interface.
Mar 03 2010
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Norbert Nemec:

 No! No! No! Design-by-contract means that it is the application's duty 
 to make sure that argument values are correct. If the program is 
 correct, the library can trust that the argument values are correct and 
 does not need to do checks. This is exactly the same situation that 
 assertions are for: Double-checking something to catch potential bugs.
 
 Exceptions are a very different issue and should never be used for this 
 purpose.
 
 A library interface simply is something different than a user interface.
Thank you, now I have understood what you mean (I did't understand your first answer to me). So you are saying that Contract Programming is not meant to be used to test for wrong inputs coming from the user interface (just like asserts). I think you are right, it is something that needs to be known. I think Michiel Helvensteijn was saying something similar. Then the D code in that Wikipedia page (http://en.wikipedia.org/wiki/Class_invariant#D ) may need to be modified again. Yet, if you note in the Java code there are extra if tests (that are not present in the Eiffel code): /* requires 1<=d && d <=31; ensures day == d; */ public void setDay(int d) { if (1 <= d && d <= 31) day = d; } Maybe that Java programmer doesn't trust the programmer, and thinks that class can receive code from an user interface. Maybe because the D library uses Contract programming, while the application code does not. What I think you are missing is that there's difference between what's the theoretically correct thing to do, and what's better to do in real code today (for example to avoid certain bugs). I am not sure how to write code yet, I'll need practice, and what I have just said can be stupid. But now I understand what's right and why, thanks to this useful discussion. I have never used Contract programming in my past languages, and I have never read books about it, so I didn't know how to use it beside knowing the D syntax to use it. I hope Andrei's book will have some pages about this too, because it's a built-in part of D. Bye, bearophile
Mar 03 2010
parent reply Norbert Nemec <Norbert Nemec-online.de> writes:
The edited Wikipedia text for D is so far correct, even though the whole 
page is not quite as precise as it could be. The theoretical basis and 
the practical application are somewhat mixed. Fixing that, however, 
would be a major task.

I think the fundamental distinction between three concepts is essential 
in understanding the issue:

* exceptions - handling of run-time conditions caused by user, file, 
network or any other kind of input. Hitting an exception is not a bug 
but a regular function of the code.

* contracts - well designed parts of interfaces. Best understood 
literally as "contract", defining who is responsible for a bug. The 
possibility to check a contract at runtime is actually a secondary function.

* assertions - best understood as "comments" that can be checked by the 
compiler. Sprinkle them freely wherever you find some non-trivial 
relation between variables of the code.

I guess this whole issue simply is something that has to be discussed 
more frequently to make people aware of it.

Greetings,
Norbert




bearophile wrote:
 Norbert Nemec:
 
 No! No! No! Design-by-contract means that it is the application's duty 
 to make sure that argument values are correct. If the program is 
 correct, the library can trust that the argument values are correct and 
 does not need to do checks. This is exactly the same situation that 
 assertions are for: Double-checking something to catch potential bugs.

 Exceptions are a very different issue and should never be used for this 
 purpose.

 A library interface simply is something different than a user interface.
Thank you, now I have understood what you mean (I did't understand your first answer to me). So you are saying that Contract Programming is not meant to be used to test for wrong inputs coming from the user interface (just like asserts). I think you are right, it is something that needs to be known. I think Michiel Helvensteijn was saying something similar. Then the D code in that Wikipedia page (http://en.wikipedia.org/wiki/Class_invariant#D ) may need to be modified again. Yet, if you note in the Java code there are extra if tests (that are not present in the Eiffel code): /* requires 1<=d && d <=31; ensures day == d; */ public void setDay(int d) { if (1 <= d && d <= 31) day = d; } Maybe that Java programmer doesn't trust the programmer, and thinks that class can receive code from an user interface. Maybe because the D library uses Contract programming, while the application code does not. What I think you are missing is that there's difference between what's the theoretically correct thing to do, and what's better to do in real code today (for example to avoid certain bugs). I am not sure how to write code yet, I'll need practice, and what I have just said can be stupid. But now I understand what's right and why, thanks to this useful discussion. I have never used Contract programming in my past languages, and I have never read books about it, so I didn't know how to use it beside knowing the D syntax to use it. I hope Andrei's book will have some pages about this too, because it's a built-in part of D. Bye, bearophile
Mar 03 2010
parent reply Brad Roberts <braddr bellevue.puremagic.com> writes:
On Wed, 3 Mar 2010, Norbert Nemec wrote:

 The edited Wikipedia text for D is so far correct, even though the whole page
 is not quite as precise as it could be. The theoretical basis and the
 practical application are somewhat mixed. Fixing that, however, would be a
 major task.
 
 I think the fundamental distinction between three concepts is essential in
 understanding the issue:
 
 * exceptions - handling of run-time conditions caused by user, file, network
 or any other kind of input. Hitting an exception is not a bug but a regular
 function of the code.
 
 * contracts - well designed parts of interfaces. Best understood literally as
 "contract", defining who is responsible for a bug. The possibility to check a
 contract at runtime is actually a secondary function.
 
 * assertions - best understood as "comments" that can be checked by the
 compiler. Sprinkle them freely wherever you find some non-trivial relation
 between variables of the code.
 
 I guess this whole issue simply is something that has to be discussed more
 frequently to make people aware of it.
 
 Greetings,
 Norbert
There's an important point that's been left out of this conversation so far (unless I missed it): Asserts in the body of a method have no impact on overridden implementations in subclasses, but in/out contracts do. So there's a distinct value in using in/out for non-final methods. Later, Brad
Mar 03 2010
next sibling parent retard <re tard.com.invalid> writes:
Wed, 03 Mar 2010 14:09:59 -0800, Brad Roberts wrote:

 On Wed, 3 Mar 2010, Norbert Nemec wrote:
 
 The edited Wikipedia text for D is so far correct, even though the
 whole page is not quite as precise as it could be. The theoretical
 basis and the practical application are somewhat mixed. Fixing that,
 however, would be a major task.
 
 I think the fundamental distinction between three concepts is essential
 in understanding the issue:
 
 * exceptions - handling of run-time conditions caused by user, file,
 network or any other kind of input. Hitting an exception is not a bug
 but a regular function of the code.
 
 * contracts - well designed parts of interfaces. Best understood
 literally as "contract", defining who is responsible for a bug. The
 possibility to check a contract at runtime is actually a secondary
 function.
 
 * assertions - best understood as "comments" that can be checked by the
 compiler. Sprinkle them freely wherever you find some non-trivial
 relation between variables of the code.
 
 I guess this whole issue simply is something that has to be discussed
 more frequently to make people aware of it.
 
 Greetings,
 Norbert
There's an important point that's been left out of this conversation so far (unless I missed it): Asserts in the body of a method have no impact on overridden implementations in subclasses, but in/out contracts do. So there's a distinct value in using in/out for non-final methods.
The fact is also mentioned here: http://en.wikipedia.org/wiki/Design_by_contract "Subclasses in an inheritance hierarchy are allowed to weaken preconditions (but not strengthen them) and strengthen postconditions and invariants (but not weaken them). These rules approximate behavioral subtyping."
Mar 03 2010
prev sibling parent Norbert Nemec <Norbert Nemec-online.de> writes:
Brad Roberts wrote:
 On Wed, 3 Mar 2010, Norbert Nemec wrote:
 
 The edited Wikipedia text for D is so far correct, even though the whole page
 is not quite as precise as it could be. The theoretical basis and the
 practical application are somewhat mixed. Fixing that, however, would be a
 major task.

 I think the fundamental distinction between three concepts is essential in
 understanding the issue:

 * exceptions - handling of run-time conditions caused by user, file, network
 or any other kind of input. Hitting an exception is not a bug but a regular
 function of the code.

 * contracts - well designed parts of interfaces. Best understood literally as
 "contract", defining who is responsible for a bug. The possibility to check a
 contract at runtime is actually a secondary function.

 * assertions - best understood as "comments" that can be checked by the
 compiler. Sprinkle them freely wherever you find some non-trivial relation
 between variables of the code.

 I guess this whole issue simply is something that has to be discussed more
 frequently to make people aware of it.

 Greetings,
 Norbert
There's an important point that's been left out of this conversation so far (unless I missed it): Asserts in the body of a method have no impact on overridden implementations in subclasses, but in/out contracts do. So there's a distinct value in using in/out for non-final methods.
Perhaps, I should have been more precise in what I meant with the words "well designed parts of interfaces": If you study the original design of Eiffel by Bertrand Meyer, you will find that classes are strictly separated into interface and implementation. Contracts are part of the interface, so they are indeed inherited. When overriding a method, the input contract ("demands") can only be relaxed while the output contract ("promises") can only be tightened so that whichever code is correct in using the parent class is still correct using any inheriting class. To allow full support of Contract Programming in D, interfaces should allow contracts as well. For overriding methods the input contract should be "or"ed with the parents contracts while the output contract should be "and"ed with the parents contracts.
Mar 04 2010
prev sibling next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Norbert Nemec:
 No! No! No! Design-by-contract means that it is the application's duty 
 to make sure that argument values are correct. If the program is 
 correct, the library can trust that the argument values are correct and 
 does not need to do checks. This is exactly the same situation that 
 assertions are for: Double-checking something to catch potential bugs.
 
 Exceptions are a very different issue and should never be used for this 
 purpose.
 
 A library interface simply is something different than a user interface.
The page is modified according to your words and ideas, with just a bit of warning from the real world: http://en.wikipedia.org/wiki/Class_invariant#D Thank you, bye, bearophile
Mar 03 2010
prev sibling parent reply Lionello Lunesu <lio lunesu.remove.com> writes:
You make a good point, but there's one problem I have with this.

I'm looking at this as a library writer. I can write in-contracts with
assertions, but I would not feel comfortable with only assertions, since
I know they will not get compiled in a release build of the library.

So in a release build I don't want anything weird to happen when wrong
arguments are passed to my library function. This can only be prevented
by throwing run-time exceptions, right?

L.

On 4-3-2010 3:04, Norbert Nemec wrote:
 Lionello Lunesu wrote:
 On 2-3-2010 20:44, bearophile wrote:
 What do you think? Do you agree that's better to use exceptions like
 this to test arguments in public methods (instead of using asserts in
 preconditions)?
I agree with you. I also prefer exceptions for illegal argument values. I test them with asserts only in private methods.
No! No! No! Design-by-contract means that it is the application's duty to make sure that argument values are correct. If the program is correct, the library can trust that the argument values are correct and does not need to do checks. This is exactly the same situation that assertions are for: Double-checking something to catch potential bugs. Exceptions are a very different issue and should never be used for this purpose. A library interface simply is something different than a user interface.
Mar 03 2010
next sibling parent Norbert Nemec <Norbert Nemec-online.de> writes:
That sounds pretty much like putting your application authors under 
tutelage (great word - just found it in the dictionary... :-) )

Writing a library that other can use, you should always assume that they 
are mature and responsible beings. The contracts explicitly tell the 
application author their responsibilities. Checking the contracts 
provides a safety net for the application author. If the author decides 
to deactivate this safety net, you should allow them to do so.

Ultimately, the language provides everything that would allow a compiler 
to offer fine-tuned switching of checks. It should be straightforward to 
implement an option to activate only checks of public contracts between 
libraries, but this decision should be up to the application programmer 
who is responsible that the whole package works as it should.

After all: The whole D language is built on the concept of providing 
professional tools for responsible programmers. If someone decides to 
shoot himself in the foot, at least give him a quality gun that allows 
him to aim properly!




Lionello Lunesu wrote:
 You make a good point, but there's one problem I have with this.
 
 I'm looking at this as a library writer. I can write in-contracts with
 assertions, but I would not feel comfortable with only assertions, since
 I know they will not get compiled in a release build of the library.
 
 So in a release build I don't want anything weird to happen when wrong
 arguments are passed to my library function. This can only be prevented
 by throwing run-time exceptions, right?
Mar 04 2010
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 03 Mar 2010 18:58:54 -0500, Lionello Lunesu  
<lio lunesu.remove.com> wrote:

 You make a good point, but there's one problem I have with this.

 I'm looking at this as a library writer. I can write in-contracts with
 assertions, but I would not feel comfortable with only assertions, since
 I know they will not get compiled in a release build of the library.
Contracts and invariants also are not compiled in a release build of the library. -Steve
Mar 04 2010