digitalmars.D - against enforce
- Kagamin (2/4) Mar 25 2011 So why do you need to differentiate between assert and enforce if you ca...
- Alix Pexton (33/37) Mar 25 2011 I can't think of an occasion when I would want to have my uses of
- Jonathan M Davis (51/60) Mar 25 2011 assert and enforce serve _very_ different purposes. assert is for checki...
- Kagamin (4/14) Mar 25 2011 I believe, sometimes it's easier to make sure that the input is correct,...
- bearophile (4/5) Mar 25 2011 I presume this problem will be fixed "soon", probably with two versions ...
- spir (24/83) Mar 25 2011 This logic certainly looks sensible, but I cannot understand how it shou...
- Steven Schveighoffer (48/52) Mar 25 2011 You can look at it in a simple way: If this branch of code will always ...
- spir (15/64) Mar 25 2011 I agree with all of this. But here you're the client of sqrt. What if yo...
- Steven Schveighoffer (11/56) Mar 28 2011 The issue isn't so much that you should or should not catch errors, the ...
- Kagamin (2/5) Mar 28 2011 Optimization is not a question of error catching, only if it's smart eno...
- Steven Schveighoffer (32/40) Mar 28 2011 Yes, the instrument is too blunt, which is why we are having this
- Alix Pexton (23/43) Mar 25 2011 Since I started programming in D, unittests have been among the first
- Jonathan M Davis (28/118) Mar 25 2011 Steve has a great reply, but I'll add a bit. You use assertions where yo...
- spir (13/19) Mar 25 2011 But catching wrong arguments to math functions at *runtime* is precisely...
- Don (21/44) Mar 26 2011 That one is done by the CPU, as mentioned in another post. But it does
- spir (14/54) Mar 26 2011 Very interesting points of view, than you! Especially
- Jonathan M Davis (17/52) Mar 26 2011 Whereas I _rarely_ use in contracts. In most cases, I favor exceptions,
- Don (6/61) Mar 28 2011 If you only have standalone functions, at the moment there's not really
- Jonathan M Davis (5/74) Mar 28 2011 What's even more surprising is how invariants sometimes find bugs in _ot...
- Walter Bright (5/8) Mar 28 2011 In and out contracts come into their own when you're using inheritance. ...
- Steven Schveighoffer (5/8) Mar 28 2011 Well, if you have code in your in/out contracts that is not an assert
- Jonathan M Davis (4/21) Mar 25 2011 Don would know better than I do, but I believe that that is a CPU thing ...
- Kagamin (2/7) Mar 26 2011 I don't think it's a terminological question, it's a practical question,...
- Kagamin (2/13) Mar 26 2011 pure function called on literals is evaluatable at compile time together...
- Steven Schveighoffer (8/24) Mar 28 2011 It's not that simple.
- spir (7/27) Mar 26 2011 All right!
- Kagamin (4/12) Mar 28 2011 So why do you need a feature, which you don't use?
- Jonathan M Davis (15/32) Mar 28 2011 1. I do use it sometimes, just not often.
So, there really is no good answer. - Jonathan M DavisSo why do you need to differentiate between assert and enforce if you can't choose, which of them should be used? We can't really turn off both of them, and if we really want performance and no checks, we would want to turn off both of them, so they should work in the same way, shouldn't they?
Mar 25 2011
On 25/03/2011 08:04, Kagamin wrote:I can't think of an occasion when I would want to have my uses of enforce() stripped for a release build. Removing asserts once I am sure that my code has no logic errors make sense, but removing the code that validates user input and system integrity doesn't. Performance is irrelevant if you are processing corrupted memory or malformed input. Before there we had enforce, I did tend to use assert for both cases as I cobbled code together, then rewrite the validation parts as throws on the second pass. When enforce appeared that 2 phase process got much easier, and now I can choose the right one as I code, which increases productivity. Enforce does not replace assert, it compliments it, and very elegantly so. <aside> With regard to libraries, there is an overlap between what is input validation and what is logic checking (a logic error in the code of program a, results in bad input being sent to lib b). Here, assert is the only choice as hitting an assert in a library (hopefully) exposes logic errors in the program that uses the library, this is something that you fix by reviewing your code, not by recovering at runtime and trying again. This means that libraries (should) have 2 types of assert, but I hesitate to suggest the creation of a synonym to help better document the difference between them, as I find that the use of in{} and out{} do a pretty good job of that already. The only problems that I foresee are for libraries where the source is not available (which I have not had an issue with yet) and libs that wrap non-D code that does not use the same conventions. In these cases, one will not always know if the -release flag (or equivalent) has been used. If it has, then one may not find logic errors as one codes, if it hasn't then one will find the errors, but will not be able to strip the asserts when producing one's own release build. </aside> A...So, there really is no good answer. - Jonathan M DavisSo why do you need to differentiate between assert and enforce if you can't choose, which of them should be used? We can't really turn off both of them, and if we really want performance and no checks, we would want to turn off both of them, so they should work in the same way, shouldn't they?
Mar 25 2011
assert and enforce serve _very_ different purposes. assert is for checking the logic of your code. It can go away, so you can't rely on it. It's simply for additional checks in your code to ensure that it's of high quality. You can't rely on it. It's also _not_ for error handling. When an assertion fails, there is a bug in your program. Exceptions - and therefore enforce - are for error handling. They are supposed to _always_ be there. Performance has nothing to do with them (other than the fact that they can obviously harm performance, which may cause you to refactor your code so that they're not necessary). Typically, exceptions - and therefore enforce - are used when validating input. That input is often completely dependent on the particular run of the program, and bad input isn't necessarily a bug in the program at all. When enforce fails, that does _not_ necessarily indicate a bug in your program, and it should _not_ be used for finding bugs. Input from the user is obviously always input, and you're going to have to check that and throw an exception on failure rather than use assertions. Input to a function which is completely local to your code is not in any API anywhere and whose input is completely controlled by your code should use assertions. At that point, if the function gets bad input, it's a bug in your code. Also, out blocks, invariants, and checks in the middle of functions typically have _nothing_ to do with input and should be assertions. If they fail it's a logic bug. The problem is when a function could be both used internally and used on user input. For instance, iota is typically given hard-coded values - iota(5, 100, 2) - but you could pass it value which was given to main - iota(5, 100, to!int(args[1]). With hard-coded values, assert is the correct solution. But with user input, enforce would be. So, which do you do? assert or enforce? In the case of iota, since it is almost always used with hard-coded values and even when it isn't, it's likely used with computed values rather than user input, so if it's wrong, it's a bug in the code rather than bad user input. The application can check (with enforce or with an if and throwing an exception or whatever) that the input is good before passing it to iota if that's what it's doing. With other functions though, it's less clear. And with every such function, a choice must be made. Should it treat its input as user input or as values local to the program? If it's user input, then it needs to use exceptions. If it's local to the program (at which point a bad value would be a bug in the program), then assert should be used. And when you're dealing with a library, it's not as clear what the best solution should be in. The fact that assertions are almost certainly going to be compiled out might make it so that you want to treat input to the library's API as user input rather than local to the program when you would choose to have those same functions be treated as local to the program if they weren't in another library (though of course, there are plenty of cases where API functions should just plain be treating input as user input regardless). So, there is a clear and distinct difference between the intended uses of assert and exceptions (and therefore enforce). They have very different roles. The question then is not what their roles are but what you need a particular function to do - e.g. treat it's input as user input or treat it as local to the program (and therefore a bug if it's wrong). - Jonathan M DavisSo, there really is no good answer. - Jonathan M DavisSo why do you need to differentiate between assert and enforce if you can't choose, which of them should be used? We can't really turn off both of them, and if we really want performance and no checks, we would want to turn off both of them, so they should work in the same way, shouldn't they?
Mar 25 2011
I can't think of an occasion when I would want to have my uses of enforce() stripped for a release build.Ideally enforce shouldn't have side effects, so its removal shouldn't affect your business logic.Removing asserts once I am sure that my code has no logic errors make senseDid you ever have this sense? Well, I can be sure "hello world" has no bugs, but for something more complex... only if you're a programming god, but even then your way won't suit us mortals.Performance is irrelevant if you are processing corrupted memory or malformed input.I believe, sometimes it's easier to make sure that the input is correct, than to make sure the code has no bugs.This means that libraries (should) have 2 types of assert, but I hesitate to suggest the creation of a synonym to help better document the difference between them, as I find that the use of in{} and out{} do a pretty good job of that already.So you suggest to check iota's input in contract? They say, phobos is compiled with -release flag, so all contracts are removed. Is it ok for D programmers?
Mar 25 2011
Kagamin:They say, phobos is compiled with -release flag, so all contracts are removed.I presume this problem will be fixed "soon", probably with two versions of Phobos in the standard distribution. Otherwise D contract programming loses a significant part of its meaning and usefulness. Bye, bearophile
Mar 25 2011
On 03/25/2011 08:21 PM, Jonathan M Davis wrote:This logic certainly looks sensible, but I cannot understand how it should work in practice. Say I'm implementing a little set of operations on decimals. Among those, some (division, square root...) will necessarily have to check their input. According to the rationale you expose, I should use assertions, since operand will nearly never be (direct) user input, instead be products of the app's logic. Then, what happens when div gets a null denominator on a release build? In practice, the issue is not that serious since I will certainly delegate to a lower-level func which itself throws. But I could also (in theory) implement it in assembly or whatnot. My point of view is if a func has preconditions on its args, then checkings simply cannot go away. Such considerations lead me to wonder whether we should not instead use exceptions/enforce everywhere for actual func arg checking, and use asserts in unittests only. Or use them also for /temporary/ additional checkings during development (similar to unittests in fact). A special case may be about checkings that control logical values or ranges which do not prevent the func to run. Say, a.length should logically be in 1..9 -- but the func can run fine anyway. Denis -- _________________ vita es estrany spir.wikidot.comassert and enforce serve _very_ different purposes. assert is for checking the logic of your code. It can go away, so you can't rely on it. It's simply for additional checks in your code to ensure that it's of high quality. You can't rely on it. It's also _not_ for error handling. When an assertion fails, there is a bug in your program. Exceptions - and therefore enforce - are for error handling. They are supposed to _always_ be there. Performance has nothing to do with them (other than the fact that they can obviously harm performance, which may cause you to refactor your code so that they're not necessary). Typically, exceptions - and therefore enforce - are used when validating input. That input is often completely dependent on the particular run of the program, and bad input isn't necessarily a bug in the program at all. When enforce fails, that does _not_ necessarily indicate a bug in your program, and it should _not_ be used for finding bugs. Input from the user is obviously always input, and you're going to have to check that and throw an exception on failure rather than use assertions. Input to a function which is completely local to your code is not in any API anywhere and whose input is completely controlled by your code should use assertions. At that point, if the function gets bad input, it's a bug in your code. Also, out blocks, invariants, and checks in the middle of functions typically have _nothing_ to do with input and should be assertions. If they fail it's a logic bug. The problem is when a function could be both used internally and used on user input. For instance, iota is typically given hard-coded values - iota(5, 100, 2) - but you could pass it value which was given to main - iota(5, 100, to!int(args[1]). With hard-coded values, assert is the correct solution. But with user input, enforce would be. So, which do you do? assert or enforce? In the case of iota, since it is almost always used with hard-coded values and even when it isn't, it's likely used with computed values rather than user input, so if it's wrong, it's a bug in the code rather than bad user input. The application can check (with enforce or with an if and throwing an exception or whatever) that the input is good before passing it to iota if that's what it's doing. With other functions though, it's less clear. And with every such function, a choice must be made. Should it treat its input as user input or as values local to the program? If it's user input, then it needs to use exceptions. If it's local to the program (at which point a bad value would be a bug in the program), then assert should be used. And when you're dealing with a library, it's not as clear what the best solution should be in. The fact that assertions are almost certainly going to be compiled out might make it so that you want to treat input to the library's API as user input rather than local to the program when you would choose to have those same functions be treated as local to the program if they weren't in another library (though of course, there are plenty of cases where API functions should just plain be treating input as user input regardless). So, there is a clear and distinct difference between the intended uses of assert and exceptions (and therefore enforce). They have very different roles. The question then is not what their roles are but what you need a particular function to do - e.g. treat it's input as user input or treat it as local to the program (and therefore a bug if it's wrong).So, there really is no good answer. - Jonathan M DavisSo why do you need to differentiate between assert and enforce if you can't choose, which of them should be used? We can't really turn off both of them, and if we really want performance and no checks, we would want to turn off both of them, so they should work in the same way, shouldn't they?
Mar 25 2011
On Fri, 25 Mar 2011 16:23:08 -0400, spir <denis.spir gmail.com> wrote:This logic certainly looks sensible, but I cannot understand how it should work in practice. Say I'm implementing a little set of operations on decimals. Among those, some (division, square root...) will necessarily have to check their input.You can look at it in a simple way: If this branch of code will always run the same way every time (i.e. is deterministic), then using assert is desired. Why? Because the assumption is that you test that code via unit tests. Once you test it, and it works, there is no reason to test it again. For example, if I do: sqrt(1); There is never ever a need to test this in production code. sqrt(1) is always 1, and will always work. If I do: sqrt(-1); There is never ever a need to test this in production code. sqrt(-1) is always a failure, and will always fail. Unit tests should catch this code before it is released. But if I do something like: auto file = File.open("/tmp/xyz.txt"); // did not look up usage for File, may be wrong Then I always want this to be tested, even in release mode, because there are environments beyond the program's control that will cause an error. Similar to this, user input needs to be validated even in production code. So if you had: int main(string[] args) { sqrt(to!int(args[0])); } this means args[0] should be checked that it is a valid positive integer. The problem with this whole utopian idea is, the code that is responsible for knowing how to check its input is the function. The code that knows whether the input needs to be checked during release is the caller. So there is no way to convey to sqrt "hey, this input I'm sending in is externally-generated, check it during production too, ok?". If we had options for that, the API quickly becomes unwieldly. Of course, knowing that sqrt takes only positive numbers, we could do this check outside the sqrt function, but far more complex functions may not be so easy to validate input for. And why should the caller be responsible for validating the input? What I feel like we need is a compiler feature like: validate(sqrt(to!int(args[0])); which essentially calls sqrt with asserts and contracts *enabled*, even at production time. This way you could choose while writing code how essential a particular call is to check the input, but re-use the already-in-place contracts for that function. This might be a feature that's totally not worth the effort. But I can't see a good way to solve this without having some sort of mechanism. It also shouldn't throw an AssertError, since that would kill the program instantly. -Steve
Mar 25 2011
On 03/25/2011 09:49 PM, Steven Schveighoffer wrote:On Fri, 25 Mar 2011 16:23:08 -0400, spir <denis.spir gmail.com> wrote:I agree with all of this. But here you're the client of sqrt. What if you implement it (or for a new numeric type)? You'll need to catch param errors for /input/ to your func (not for args you /provide/ to a third party func). That was my case.This logic certainly looks sensible, but I cannot understand how it should work in practice. Say I'm implementing a little set of operations on decimals. Among those, some (division, square root...) will necessarily have to check their input.You can look at it in a simple way: If this branch of code will always run the same way every time (i.e. is deterministic), then using assert is desired. Why? Because the assumption is that you test that code via unit tests. Once you test it, and it works, there is no reason to test it again. For example, if I do: sqrt(1); There is never ever a need to test this in production code. sqrt(1) is always 1, and will always work. If I do: sqrt(-1); There is never ever a need to test this in production code. sqrt(-1) is always a failure, and will always fail. Unit tests should catch this code before it is released. But if I do something like: auto file = File.open("/tmp/xyz.txt"); // did not look up usage for File, may be wrongThen I always want this to be tested, even in release mode, because there are environments beyond the program's control that will cause an error. Similar to this, user input needs to be validated even in production code. So if you had: int main(string[] args) { sqrt(to!int(args[0])); } this means args[0] should be checked that it is a valid positive integer.Agreed. Anyway, validating input, wherever it comes from, as soon as possible, is certainly better practice. (obviously makes debugging easier)The problem with this whole utopian idea is, the code that is responsible for knowing how to check its input is the function. The code that knows whether the input needs to be checked during release is the caller. So there is no way to convey to sqrt "hey, this input I'm sending in is externally-generated, check it during production too, ok?". If we had options for that, the API quickly becomes unwieldly. Of course, knowing that sqrt takes only positive numbers, we could do this check outside the sqrt function, but far more complex functions may not be so easy to validate input for. And why should the caller be responsible for validating the input? What I feel like we need is a compiler feature like: validate(sqrt(to!int(args[0])); which essentially calls sqrt with asserts and contracts *enabled*, even at production time. This way you could choose while writing code how essential a particular call is to check the input, but re-use the already-in-place contracts for that function. This might be a feature that's totally not worth the effort. But I can't see a good way to solve this without having some sort of mechanism. It also shouldn't throw an AssertError, since that would kill the program instantly.Same for me. I'd like to find a language that implements this and see how the feature stands in front of real situations, and on the long run (remember java's checked expections ;-) Denis -- _________________ vita es estrany spir.wikidot.com
Mar 25 2011
On Fri, 25 Mar 2011 23:17:53 -0400, spir <denis.spir gmail.com> wrote:On 03/25/2011 09:49 PM, Steven Schveighoffer wrote:The issue isn't so much that you should or should not catch errors, the issue is, can the error catching be *optimized out* at production time. The answer to that question is impossible for a compiler to answer, because figuring out where a parameter came from I believe is the halting problem, and impossible (currently) for a developer who can figure out the answer to handle. This is really a question of optimization, not error catching. If something will always be the same, and it has already been tested, there is no reason to test it again. -SteveOn Fri, 25 Mar 2011 16:23:08 -0400, spir <denis.spir gmail.com> wrote:I agree with all of this. But here you're the client of sqrt. What if you implement it (or for a new numeric type)? You'll need to catch param errors for /input/ to your func (not for args you /provide/ to a third party func). That was my case.This logic certainly looks sensible, but I cannot understand how it should work in practice. Say I'm implementing a little set of operations on decimals. Among those, some (division, square root...) will necessarily have to check their input.You can look at it in a simple way: If this branch of code will always run the same way every time (i.e. is deterministic), then using assert is desired. Why? Because the assumption is that you test that code via unit tests. Once you test it, and it works, there is no reason to test it again. For example, if I do: sqrt(1); There is never ever a need to test this in production code. sqrt(1) is always 1, and will always work. If I do: sqrt(-1); There is never ever a need to test this in production code. sqrt(-1) is always a failure, and will always fail. Unit tests should catch this code before it is released. But if I do something like: auto file = File.open("/tmp/xyz.txt"); // did not look up usage for File, may be wrong
Mar 28 2011
Steven Schveighoffer Wrote:This is really a question of optimization, not error catching. If something will always be the same, and it has already been tested, there is no reason to test it again.Optimization is not a question of error catching, only if it's smart enough to not interfere with error catching, but we have only blunt method of -release switch. Thus optimization becomes question of error catching.
Mar 28 2011
On Mon, 28 Mar 2011 10:28:04 -0400, Kagamin <spam here.lot> wrote:Steven Schveighoffer Wrote:Yes, the instrument is too blunt, which is why we are having this discussion ;) But the question is still not *whether* to test for errors but *when*. The ideal is to avoid testing for them when they could not possibly occur (i.e. after testing during development proves there is no error). The whole point of using assert and contracts only in development code is so you can instrument all your code with comprehensive, possibly slow performing, tests while testing, and take them all out for shipping. But the mechanisms provided do not allow expression of when an error can occur (during testing or during production) *per call*, only per function. We need it per call to be correct. Made even more difficult is that we are discussing library functions, which can't possibly know whether to test the inputs they get unless the functions are private. You can take the "better safe than fast" approach, but it leaves no room for performance upgrades (as shown by the poor performance of phobos in comparison tests by the likes of bearophile and others). You can take the "not my problem" approach and leave it up to the caller to test inputs, but we don't provide an easy way for a user to test inputs in production code for when its needed at production time. My opinion is that Phobos should opt for "not my problem" because 90% of the time, the input comes from deterministic sources that only need be tested during development. All we need for that is a phobos compiled in non-release mode to test against. It's always possible to add more tests *outside* the phobos call for when they are needed. Then we should look into adding ways to have functions specify how to test their inputs during production in a DRY way. But of course, this path makes code that uses Phobos more prone to errors. It may be worth having all the enforce checks if we can do something like prevent all buffer overflow attacks. I'm not sure of the right answer. -SteveThis is really a question of optimization, not error catching. If something will always be the same, and it has already been tested, there is no reason to test it again.Optimization is not a question of error catching, only if it's smart enough to not interfere with error catching, but we have only blunt method of -release switch. Thus optimization becomes question of error catching.
Mar 28 2011
On 25/03/2011 20:23, spir wrote:This logic certainly looks sensible, but I cannot understand how it should work in practice. Say I'm implementing a little set of operations on decimals. Among those, some (division, square root...) will necessarily have to check their input. According to the rationale you expose, I should use assertions, since operand will nearly never be (direct) user input, instead be products of the app's logic. Then, what happens when div gets a null denominator on a release build? In practice, the issue is not that serious since I will certainly delegate to a lower-level func which itself throws. But I could also (in theory) implement it in assembly or whatnot. My point of view is if a func has preconditions on its args, then checkings simply cannot go away. Such considerations lead me to wonder whether we should not instead use exceptions/enforce everywhere for actual func arg checking, and use asserts in unittests only. Or use them also for /temporary/ additional checkings during development (similar to unittests in fact). A special case may be about checkings that control logical values or ranges which do not prevent the func to run. Say, a.length should logically be in 1..9 -- but the func can run fine anyway. DenisSince I started programming in D, unittests have been among the first things I write, and I am just about getting the hang of using DMD's coverage features to make sure that my tests cover every branch of my code. Recently I have been trying to write unittests without using any additional asserts, making unittests into examples of use, designed to hit every corner case while "telling a story". I don't find it quite as easy as just writing asserts, but it is a half step toward writing decent documentation, (something I often fail at >< ) and it makes the code to be tested easier to write. With the iota case, I want it to use assert, not enforce. I write my test so that when it runs it hits the corner cases and if there is a problem with the arguments sent to iota then execution stops in the library code. In this scenario, I know there is something I need to fix in my code (or possibly in Phobos ^^ ). If iota instead threw an exception, I would then have to put in a try/catch or a scope() and try to recover (to do otherwise would be to duplicate code already in the library), but that doesn't fix the problem, it just masks it, so my program has gotten worse, not better! That a compiled lib (including the Phobos lib distributed with DMD) is assert-less for performance reasons, is a quality of implementation issue, not a fault of enforce, or something it was ever intended to fix. A...
Mar 25 2011
On 03/25/2011 08:21 PM, Jonathan M Davis wrote:Steve has a great reply, but I'll add a bit. You use assertions where you can afford to not have the check take place (since, if it's compiled in release mode it won't). If an assertion fails, it's a bug in your code, but you can't rely on the assertion being there. If it's not a bug in your code if it fails, then you'd use an exception. Generally, you use unit testing and running the program in non-release mode to make sure that the assertions never fail. There has been some talk of adding an assertAlways which is an assertion which sticks around in release (presumably, it would be the same as enforce but throw an AssertError). But you can do that already by using enforce with an AssertError rather than Exception. So, assertions are used to ensure that your code is correct, not to report errors. In the case of something like dividing by 0 or other math functions that could be given bad values, the typical solution is to either use an assertion (or check nothing) and then let the caller worry about it. It would be extremely wasteful to have to constantly check whether the arguments to typical math functions are valid. They almost always are, and those types of functions needto be really efficient. As Steve points out, what we really need is a way to have the caller indicate whether they want an in contract to be run or not (or possibly whether it should throw or be an assertion), but no one has ever come up with a good way of doing that AFAIK. Stuff like in contracts are an implementation detail of a function and are frequently compiled out. You'd have to no longer quite treat a function as something that's simply called and returns a value. You'd need it to have the concept of validation code which went along with the function and which the caller could choose to call or not. And I'm not sure that you can really do that with the C linking model. - Jonathan M DavisThis logic certainly looks sensible, but I cannot understand how it should work in practice. Say I'm implementing a little set of operations on decimals. Among those, some (division, square root...) will necessarily have to check their input. According to the rationale you expose, I should use assertions, since operand will nearly never be (direct) user input, instead be products of the app's logic. Then, what happens when div gets a null denominator on a release build? In practice, the issue is not that serious since I will certainly delegate to a lower-level func which itself throws. But I could also (in theory) implement it in assembly or whatnot. My point of view is if a func has preconditions on its args, then checkings simply cannot go away. Such considerations lead me to wonder whether we should not instead use exceptions/enforce everywhere for actual func arg checking, and use asserts in unittests only. Or use them also for /temporary/ additional checkings during development (similar to unittests in fact). A special case may be about checkings that control logical values or ranges which do not prevent the func to run. Say, a.length should logically be in 1..9 -- but the func can run fine anyway.assert and enforce serve _very_ different purposes. assert is for checking the logic of your code. It can go away, so you can't rely on it. It's simply for additional checks in your code to ensure that it's of high quality. You can't rely on it. It's also _not_ for error handling. When an assertion fails, there is a bug in your program. Exceptions - and therefore enforce - are for error handling. They are supposed to _always_ be there. Performance has nothing to do with them (other than the fact that they can obviously harm performance, which may cause you to refactor your code so that they're not necessary). Typically, exceptions - and therefore enforce - are used when validating input. That input is often completely dependent on the particular run of the program, and bad input isn't necessarily a bug in the program at all. When enforce fails, that does _not_ necessarily indicate a bug in your program, and it should _not_ be used for finding bugs. Input from the user is obviously always input, and you're going to have to check that and throw an exception on failure rather than use assertions. Input to a function which is completely local to your code is not in any API anywhere and whose input is completely controlled by your code should use assertions. At that point, if the function gets bad input, it's a bug in your code. Also, out blocks, invariants, and checks in the middle of functions typically have _nothing_ to do with input and should be assertions. If they fail it's a logic bug. The problem is when a function could be both used internally and used on user input. For instance, iota is typically given hard-coded values - iota(5, 100, 2) - but you could pass it value which was given to main - iota(5, 100, to!int(args[1]). With hard-coded values, assert is the correct solution. But with user input, enforce would be. So, which do you do? assert or enforce? In the case of iota, since it is almost always used with hard-coded values and even when it isn't, it's likely used with computed values rather than user input, so if it's wrong, it's a bug in the code rather than bad user input. The application can check (with enforce or with an if and throwing an exception or whatever) that the input is good before passing it to iota if that's what it's doing. With other functions though, it's less clear. And with every such function, a choice must be made. Should it treat its input as user input or as values local to the program? If it's user input, then it needs to use exceptions. If it's local to the program (at which point a bad value would be a bug in the program), then assert should be used. And when you're dealing with a library, it's not as clear what the best solution should be in. The fact that assertions are almost certainly going to be compiled out might make it so that you want to treat input to the library's API as user input rather than local to the program when you would choose to have those same functions be treated as local to the program if they weren't in another library (though of course, there are plenty of cases where API functions should just plain be treating input as user input regardless). So, there is a clear and distinct difference between the intended uses of assert and exceptions (and therefore enforce). They have very different roles. The question then is not what their roles are but what you need a particular function to do - e.g. treat it's input as user input or treat it as local to the program (and therefore a bug if it's wrong).So, there really is no good answer. - Jonathan M DavisSo why do you need to differentiate between assert and enforce if you can't choose, which of them should be used? We can't really turn off both of them, and if we really want performance and no checks, we would want to turn off both of them, so they should work in the same way, shouldn't they?
Mar 25 2011
On 03/25/2011 11:20 PM, Jonathan M Davis wrote:In the case of something like dividing by 0 or other math functions that could be given bad values, the typical solution is to either use an assertion (or check nothing) and then let the caller worry about it. It would be extremely wasteful to have to constantly check whether the arguments to typical math functions are valid. They almost always are, and those types of functions needto be really efficient.But catching wrong arguments to math functions at *runtime* is precisely what D itself does (as well as all languages I know): auto a = 1, b = 0; auto c = a/b; ==> Floating point exception There is no way out, or do I miss a point? Denis -- _________________ vita es estrany spir.wikidot.com
Mar 25 2011
spir wrote:On 03/25/2011 11:20 PM, Jonathan M Davis wrote:That one is done by the CPU, as mentioned in another post. But it does illustrate something interesting: the contract programming makes you think there is a symmetry between in and out contracts, whereas in fact they have very little in common. If an out contract fails, it ALWAYS indicates a bug in the function. So it should ALWAYS be an assert. But 'in' contracts are completely different, since they indicate a problem in the calling code. (Personally I cannot see the value of 'out' contracts, except as information for verifying later 'in' contracts). When I started writing D code, I originally used 'in' contracts frequently in my mathematical code. But later, I removed most of them. Why? Because including a particular condition in a 'in' contract makes it undefined behaviour in release mode! So you need to be clear, is this parameter value a runtime error, or is it a bug in the calling code? In most mathematical code, you want it to be an error -- you don't normally want undefined behaviour for particular inputs. If the requirements for valid parameter values are complicated, you're placing a huge burden on the caller if you include asserts, making them bugs. In summary: enforce is nice for the caller, assert is nice for the callee. The decision of whom to favour can be tricky.In the case of something like dividing by 0 or other math functions that could be given bad values, the typical solution is to either use an assertion (or check nothing) and then let the caller worry about it. It would be extremely wasteful to have to constantly check whether the arguments to typical math functions are valid. They almost always are, and those types of functions needto be really efficient.But catching wrong arguments to math functions at *runtime* is precisely what D itself does (as well as all languages I know): auto a = 1, b = 0; auto c = a/b; ==> Floating point exception There is no way out, or do I miss a point? Denis
Mar 26 2011
On 03/26/2011 04:55 PM, Don wrote:spir wrote:Very interesting points of view, than you! Especially * making the misleading symmetry between 'in' & 'out' contracts (==> importance of *naming*, again!) * the relative weakness of in contracts or asserts. About 'out' contracts, I know see them as an alternate way of testing, during development or maintenance. Kinds of constant assertions (in the logical sense) checked there, which may help catching bugs, and before all do not need to be checked in unittests. Denis -- _________________ vita es estrany spir.wikidot.comOn 03/25/2011 11:20 PM, Jonathan M Davis wrote:That one is done by the CPU, as mentioned in another post. But it does illustrate something interesting: the contract programming makes you think there is a symmetry between in and out contracts, whereas in fact they have very little in common. If an out contract fails, it ALWAYS indicates a bug in the function. So it should ALWAYS be an assert. But 'in' contracts are completely different, since they indicate a problem in the calling code. (Personally I cannot see the value of 'out' contracts, except as information for verifying later 'in' contracts). When I started writing D code, I originally used 'in' contracts frequently in my mathematical code. But later, I removed most of them. Why? Because including a particular condition in a 'in' contract makes it undefined behaviour in release mode! So you need to be clear, is this parameter value a runtime error, or is it a bug in the calling code? In most mathematical code, you want it to be an error -- you don't normally want undefined behaviour for particular inputs. If the requirements for valid parameter values are complicated, you're placing a huge burden on the caller if you include asserts, making them bugs. In summary: enforce is nice for the caller, assert is nice for the callee. The decision of whom to favour can be tricky.In the case of something like dividing by 0 or other math functions that could be given bad values, the typical solution is to either use an assertion (or check nothing) and then let the caller worry about it. It would be extremely wasteful to have to constantly check whether the arguments to typical math functions are valid. They almost always are, and those types of functions needto be really efficient.But catching wrong arguments to math functions at *runtime* is precisely what D itself does (as well as all languages I know): auto a = 1, b = 0; auto c = a/b; ==> Floating point exception There is no way out, or do I miss a point? Denis
Mar 26 2011
On 2011-03-26 08:55, Don wrote:spir wrote:Whereas I _rarely_ use in contracts. In most cases, I favor exceptions, treating my functions as API functions pretty much as long as they're public. That's not always the best approach, but it's generally what I end up using. invariants, I use fairly frequently (and in fact have run into trouble due to issues with them - e.g. http://d.puremagic.com/issues/show_bug.cgi?id=5058 ). out, on the other hand, I don't use as much. It's not terribly common that there's a good test to run on the return value of a function in my experience. Upon occasion, it's useful, but rarely. Unit tests generally solve the problem better with regards to testing output. They're still useful though - just not commonly so. So, honestly, other than invariants, I don't use D's DbC much. in contracts get used upon occasion, but I tend to favor exceptions over assertions in most cases, so I don't use in all that often, and while out is occasionally useful, unit tests generally do a better job of verifying that a function's return value is correct. I'm _very_ glad to have invariants though. - Jonathan M DavisOn 03/25/2011 11:20 PM, Jonathan M Davis wrote:That one is done by the CPU, as mentioned in another post. But it does illustrate something interesting: the contract programming makes you think there is a symmetry between in and out contracts, whereas in fact they have very little in common. If an out contract fails, it ALWAYS indicates a bug in the function. So it should ALWAYS be an assert. But 'in' contracts are completely different, since they indicate a problem in the calling code. (Personally I cannot see the value of 'out' contracts, except as information for verifying later 'in' contracts).In the case of something like dividing by 0 or other math functions that could be given bad values, the typical solution is to either use an assertion (or check nothing) and then let the caller worry about it. It would be extremely wasteful to have to constantly check whether the arguments to typical math functions are valid. They almost always are, and those types of functions needto be really efficient.But catching wrong arguments to math functions at *runtime* is precisely what D itself does (as well as all languages I know): auto a = 1, b = 0; auto c = a/b; ==> Floating point exception There is no way out, or do I miss a point? Denis
Mar 26 2011
Jonathan M Davis wrote:On 2011-03-26 08:55, Don wrote:If you only have standalone functions, at the moment there's not really any benefit to in and out contracts. You can equally well put the asserts at the start and end of the function. I totally agree with you about invariants. I've been amazed at how many bugs can be caught by even a very trivial invariant.spir wrote:Whereas I _rarely_ use in contracts. In most cases, I favor exceptions, treating my functions as API functions pretty much as long as they're public. That's not always the best approach, but it's generally what I end up using. invariants, I use fairly frequently (and in fact have run into trouble due to issues with them - e.g. http://d.puremagic.com/issues/show_bug.cgi?id=5058 ). out, on the other hand, I don't use as much. It's not terribly common that there's a good test to run on the return value of a function in my experience. Upon occasion, it's useful, but rarely. Unit tests generally solve the problem better with regards to testing output. They're still useful though - just not commonly so. So, honestly, other than invariants, I don't use D's DbC much. in contracts get used upon occasion, but I tend to favor exceptions over assertions in most cases, so I don't use in all that often, and while out is occasionally useful, unit tests generally do a better job of verifying that a function's return value is correct. I'm _very_ glad to have invariants though. - Jonathan M DavisOn 03/25/2011 11:20 PM, Jonathan M Davis wrote:That one is done by the CPU, as mentioned in another post. But it does illustrate something interesting: the contract programming makes you think there is a symmetry between in and out contracts, whereas in fact they have very little in common. If an out contract fails, it ALWAYS indicates a bug in the function. So it should ALWAYS be an assert. But 'in' contracts are completely different, since they indicate a problem in the calling code. (Personally I cannot see the value of 'out' contracts, except as information for verifying later 'in' contracts).In the case of something like dividing by 0 or other math functions that could be given bad values, the typical solution is to either use an assertion (or check nothing) and then let the caller worry about it. It would be extremely wasteful to have to constantly check whether the arguments to typical math functions are valid. They almost always are, and those types of functions needto be really efficient.But catching wrong arguments to math functions at *runtime* is precisely what D itself does (as well as all languages I know): auto a = 1, b = 0; auto c = a/b; ==> Floating point exception There is no way out, or do I miss a point? Denis
Mar 28 2011
On 2011-03-28 00:53, Don wrote:Jonathan M Davis wrote:What's even more surprising is how invariants sometimes find bugs in _other_ code (e.g. http://d.puremagic.com/issues/show_bug.cgi?id=5500 ) instead of just the member functions of the type with the invariant. - Jonathan M DavisOn 2011-03-26 08:55, Don wrote:If you only have standalone functions, at the moment there's not really any benefit to in and out contracts. You can equally well put the asserts at the start and end of the function. I totally agree with you about invariants. I've been amazed at how many bugs can be caught by even a very trivial invariant.spir wrote:Whereas I _rarely_ use in contracts. In most cases, I favor exceptions, treating my functions as API functions pretty much as long as they're public. That's not always the best approach, but it's generally what I end up using. invariants, I use fairly frequently (and in fact have run into trouble due to issues with them - e.g. http://d.puremagic.com/issues/show_bug.cgi?id=5058 ). out, on the other hand, I don't use as much. It's not terribly common that there's a good test to run on the return value of a function in my experience. Upon occasion, it's useful, but rarely. Unit tests generally solve the problem better with regards to testing output. They're still useful though - just not commonly so. So, honestly, other than invariants, I don't use D's DbC much. in contracts get used upon occasion, but I tend to favor exceptions over assertions in most cases, so I don't use in all that often, and while out is occasionally useful, unit tests generally do a better job of verifying that a function's return value is correct. I'm _very_ glad to have invariants though. - Jonathan M DavisOn 03/25/2011 11:20 PM, Jonathan M Davis wrote:That one is done by the CPU, as mentioned in another post. But it does illustrate something interesting: the contract programming makes you think there is a symmetry between in and out contracts, whereas in fact they have very little in common. If an out contract fails, it ALWAYS indicates a bug in the function. So it should ALWAYS be an assert. But 'in' contracts are completely different, since they indicate a problem in the calling code. (Personally I cannot see the value of 'out' contracts, except as information for verifying later 'in' contracts).In the case of something like dividing by 0 or other math functions that could be given bad values, the typical solution is to either use an assertion (or check nothing) and then let the caller worry about it. It would be extremely wasteful to have to constantly check whether the arguments to typical math functions are valid. They almost always are, and those types of functions needto be really efficient.But catching wrong arguments to math functions at *runtime* is precisely what D itself does (as well as all languages I know): auto a = 1, b = 0; auto c = a/b; ==> Floating point exception There is no way out, or do I miss a point? Denis
Mar 28 2011
On 3/28/2011 12:53 AM, Don wrote:If you only have standalone functions, at the moment there's not really any benefit to in and out contracts. You can equally well put the asserts at the start and end of the function.In and out contracts come into their own when you're using inheritance. The in contract is an OR of all the overridden function in's, and the out is the AND of all the overridden out's. It's pretty clunky to do this manually. They also have a possible future use as input to a static program analyzer.
Mar 28 2011
On Mon, 28 Mar 2011 03:53:56 -0400, Don <nospam nospam.com> wrote:If you only have standalone functions, at the moment there's not really any benefit to in and out contracts. You can equally well put the asserts at the start and end of the function.Well, if you have code in your in/out contracts that is not an assert call, it will also be compiled out (not true if the in check is inside the body). -Steve
Mar 28 2011
On 2011-03-25 20:10, spir wrote:On 03/25/2011 11:20 PM, Jonathan M Davis wrote:Don would know better than I do, but I believe that that is a CPU thing there. D isn't doing that. The CPU is. - Jonathan M DavisIn the case of something like dividing by 0 or other math functions that could be given bad values, the typical solution is to either use an assertion (or check nothing) and then let the caller worry about it. It would be extremely wasteful to have to constantly check whether the arguments to typical math functions are valid. They almost always are, and those types of functions needto be really efficient.But catching wrong arguments to math functions at *runtime* is precisely what D itself does (as well as all languages I know): auto a = 1, b = 0; auto c = a/b; ==> Floating point exception There is no way out, or do I miss a point?
Mar 25 2011
Jonathan M Davis Wrote:So, there is a clear and distinct difference between the intended uses of assert and exceptions (and therefore enforce). They have very different roles. The question then is not what their roles are but what you need a particular function to do - e.g. treat it's input as user input or treat it as local to the program (and therefore a bug if it's wrong).I don't think it's a terminological question, it's a practical question, every piece of code should do something useful. Ok, assert checks for bugs. The question is should these checks be removed and why.
Mar 26 2011
Steven Schveighoffer Wrote:For example, if I do: sqrt(1); There is never ever a need to test this in production code. sqrt(1) is always 1, and will always work. If I do: sqrt(-1);pure function called on literals is evaluatable at compile time together with checks, so if sqrt run at runtime, this means input couldn't be validated that easily, so checks should be run too. This means that it's unnecessary to ever remove checks from sqrt.
Mar 26 2011
On Sat, 26 Mar 2011 08:14:19 -0400, Kagamin <spam here.lot> wrote:Steven Schveighoffer Wrote:It's not that simple. for example: sqrt(uniform(1.0, 2000.0)); This is completely safe, and needs no runtime error checks. It's easier to explain with simple examples, knowing that you can extrapolate more complex ones that the compiler can't "prove". -SteveFor example, if I do: sqrt(1); There is never ever a need to test this in production code. sqrt(1) is always 1, and will always work. If I do: sqrt(-1);pure function called on literals is evaluatable at compile time together with checks, so if sqrt run at runtime, this means input couldn't be validated that easily, so checks should be run too. This means that it's unnecessary to ever remove checks from sqrt.
Mar 28 2011
On 03/26/2011 04:31 AM, Jonathan M Davis wrote:On 2011-03-25 20:10, spir wrote:All right! Denis -- _________________ vita es estrany spir.wikidot.comOn 03/25/2011 11:20 PM, Jonathan M Davis wrote:Don would know better than I do, but I believe that that is a CPU thing there. D isn't doing that. The CPU is.In the case of something like dividing by 0 or other math functions that could be given bad values, the typical solution is to either use an assertion (or check nothing) and then let the caller worry about it. It would be extremely wasteful to have to constantly check whether the arguments to typical math functions are valid. They almost always are, and those types of functions needto be really efficient.But catching wrong arguments to math functions at *runtime* is precisely what D itself does (as well as all languages I know): auto a = 1, b = 0; auto c = a/b; ==> Floating point exception There is no way out, or do I miss a point?
Mar 26 2011
Jonathan M Davis Wrote:Whereas I _rarely_ use in contracts. In most cases, I favor exceptions, treating my functions as API functions pretty much as long as they're public. That's not always the best approach, but it's generally what I end up using.So why do you need a feature, which you don't use? Also if a feature isn't used, doesn't it mean it's useless?out, on the other hand, I don't use as much. It's not terribly common that there's a good test to run on the return value of a function in my experience. Upon occasion, it's useful, but rarely. Unit tests generally solve the problem better with regards to testing output. They're still useful though - just not commonly so.If you don't prohibit contracts to check external data, you can enforce the check at design time with out contract. How would you check that caller checks received data?
Mar 28 2011
On 2011-03-28 04:56, Kagamin wrote:Jonathan M Davis Wrote:1. I do use it sometimes, just not often. 2. Just because I don't personally use it much doesn't mean that it's useless. 3. The main place that in is supposed to shine is with inheritance trees. It handles contract inheritance.Whereas I _rarely_ use in contracts. In most cases, I favor exceptions, treating my functions as API functions pretty much as long as they're public. That's not always the best approach, but it's generally what I end up using.So why do you need a feature, which you don't use? Also if a feature isn't used, doesn't it mean it's useless?I'm afraid that I don't understand the question. out contracts are intended to verify that the result(s) of the function are correct (return value, the state of the object if it's a member variable, etc.). That's not generally very flexible in that it implies that there is a test that you can run on the result of a function to determine that the result is correct _regardless_ of the input. I don't find that to be useful very often, but sometimes it is. More often what I need is to check that given a particular input, the function gives you a particular output. And that's a job for unit tests. - Jonathan M Davisout, on the other hand, I don't use as much. It's not terribly common that there's a good test to run on the return value of a function in my experience. Upon occasion, it's useful, but rarely. Unit tests generally solve the problem better with regards to testing output. They're still useful though - just not commonly so.If you don't prohibit contracts to check external data, you can enforce the check at design time with out contract. How would you check that caller checks received data?
Mar 28 2011