digitalmars.D - Good Contract programming idiom?
- bearophile (99/99) Mar 02 2010 This is currently present in this Wikipedia page:
- Norbert Nemec (14/15) Mar 02 2010 For this statement, you should make a distinction between libraries and
- Fawzi Mohamed (7/25) Mar 02 2010 well there are checks that I want to keep also in deployment, for
- Norbert Nemec (12/45) Mar 02 2010 That strategy is fine for quick-and-dirty code, but for any code that
- dsimcha (2/4) Mar 02 2010 In D2, isn't that what enforce() is for?
- Lars T. Kyllingstad (13/18) Mar 02 2010 It is indeed.
- Lutger (15/15) Mar 02 2010 Theoretically exceptions are situations you expect can happen, even thou...
- Michiel Helvensteijn (16/19) Mar 02 2010 Short answer: No!
- bearophile (24/30) Mar 02 2010 You are probably right :-)
- Kagamin (7/8) Mar 02 2010 Never deemed -release flag as a useful thing, may be I just don't put in...
- bearophile (10/16) Mar 02 2010 -release disables array bounds tests too. This can produce D code 2-3 ti...
- Kagamin (2/4) Mar 03 2010 I've hit an array bounds error which was os-dependent. That was fearsome...
- Lutger (8/13) Mar 02 2010 The problem is this: in release mode you may be able to recover. The Dat...
- Lionello Lunesu (4/5) Mar 03 2010 I agree with you. I also prefer exceptions for illegal argument values.
- Norbert Nemec (9/14) Mar 03 2010 No! No! No! Design-by-contract means that it is the application's duty
- bearophile (17/27) Mar 03 2010 Thank you, now I have understood what you mean (I did't understand your ...
- Norbert Nemec (20/55) Mar 03 2010 The edited Wikipedia text for D is so far correct, even though the whole...
- Brad Roberts (8/33) Mar 03 2010 There's an important point that's been left out of this conversation so
- retard (7/42) Mar 03 2010 The fact is also mentioned here:
- Norbert Nemec (14/48) Mar 04 2010 Perhaps, I should have been more precise in what I meant with the words
- bearophile (5/15) Mar 03 2010 The page is modified according to your words and ideas, with just a bit ...
- Lionello Lunesu (9/28) Mar 03 2010 You make a good point, but there's one problem I have with this.
- Norbert Nemec (17/26) Mar 04 2010 That sounds pretty much like putting your application authors under
- Steven Schveighoffer (5/9) Mar 04 2010 Contracts and invariants also are not compiled in a release build of the...
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
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
On 2-mar-10, at 15:50, Norbert Nemec wrote:bearophile wrote: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...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
Fawzi Mohamed wrote:On 2-mar-10, at 15:50, Norbert Nemec wrote: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.)bearophile wrote: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...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
== Quote from Fawzi Mohamed (fawzi gmx.ch)'s articleI already thought that having a aassert (always assert) would be nice...In D2, isn't that what enforce() is for?
Mar 02 2010
dsimcha wrote:== Quote from Fawzi Mohamed (fawzi gmx.ch)'s articleIt 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. -LarsI already thought that having a aassert (always assert) would be nice...In D2, isn't that what enforce() is for?
Mar 02 2010
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
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
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
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
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
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
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
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
Lionello Lunesu wrote:On 2-3-2010 20:44, bearophile wrote: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.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.
Mar 03 2010
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
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
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, NorbertThere'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
Wed, 03 Mar 2010 14:09:59 -0800, Brad Roberts wrote:On Wed, 3 Mar 2010, Norbert Nemec wrote: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."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, NorbertThere'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.
Mar 03 2010
Brad Roberts wrote:On Wed, 3 Mar 2010, Norbert Nemec wrote: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.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, NorbertThere'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.
Mar 04 2010
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
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: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.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.
Mar 03 2010
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
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