digitalmars.D - Disallow side effects in assert
- bearophile (20/42) Feb 03 2014 A nice blog post about assertions, preconditions, invariants and
- Daniel Murphy (2/3) Feb 03 2014 Having the compiler see inside function bodies is problematic.
- bearophile (5/7) Feb 03 2014 Why do you need that? You can tell that foo() is not strongly
- Daniel Murphy (3/5) Feb 03 2014 Enough to tell it _might_ have a side effect, not enough to know it _wil...
- bearophile (7/10) Feb 03 2014 How many impure functions do you call in your asserts?
- Iain Buclaw (7/11) Feb 03 2014 Rephrase to 'How many *functions* do you call in your asserts?'
- Daniel Murphy (4/7) Feb 03 2014 Do you really want to force all codebases to 'pure'ify all their functio...
- bearophile (9/13) Feb 03 2014 What percentage of your functions are transitively called in your
- Brad Roberts (4/15) Feb 03 2014 I have one semi-large code base where I validate the locking semantics
- bearophile (5/9) Feb 03 2014 I see, and you can't you use a special library-defined assert for
- Marco Leise (13/16) Feb 03 2014 Damn those gotchas. Basically lock.try_acquire is pure when it
- bearophile (7/10) Feb 03 2014 So an annotation like the proposed @noreturn (similar to GCC
- bearophile (5/5) Feb 03 2014 If someone implements this test, we could see how many problems
- Jesse Phillips (2/13) Feb 03 2014 Aren't these things you might do inside a unittest?
- bearophile (15/16) Feb 03 2014 Mutating state and calling impure functions is OK in an unittest.
- bearophile (4/4) Feb 04 2014 An example of the problem?
- Marco Leise (11/17) Feb 04 2014 Yes, this is definitely why asserts should not have side
- bearophile (6/8) Feb 04 2014 Can't you define a impureAssert() in Phobos and use it for the
- Marco Leise (5/16) Feb 04 2014 What would happen to them in release compiles?
- bearophile (5/6) Feb 04 2014 Perhaps their body that calls the lazy argument should be wrapped
- Daniel Murphy (3/6) Feb 04 2014 Actually it only requires const-pure to prevent side effects.
A nice blog post about assertions, preconditions, invariants and their usage: http://blog.regehr.org/archives/1091 It shows how D avoids some troubles, and offers most of what's needed.The checkRep() IdiomIt could go in the D invariant. I use it often.The second way to accidentally change the state of the program is like this: assert (treeDepth() == 7); but unfortunately treeDepth() changes the value in some variable or heap cell, perhaps via a longish call chain. In case it isn't totally clear, the problem with side-effects in assertions is that we'll test our program for a while, decide it's good, and do a release build with assertions turned off and of course suddenly it doesn't work. Or, it might be the release version that works but our debug build is broken by a side-effecting assertion. Dealing with these problems is highly demoralizing since assertions are supposed to save time, not eat it up. I feel certain that there are static analyzers that warn about this kind of thing. In fact, the original paper about the work that became Coverity's tool mentions exactly this analysis in Section 4.1, and also gives plenty of examples of this bug. This is an area where language support for controlling side effects would be useful. Such support is extremely primitive in C/C++.On this topic I have recently added an Enhancement Request, to disallow side effects in assert(): https://d.puremagic.com/issues/show_bug.cgi?id=12028 Two simple examples of code that is meant to be forbidden: int foo(ref int y) pure nothrow { return y++; } void main() { int x; assert(++x); assert(foo(x)); } Bye, bearophile
Feb 03 2014
"bearophile" wrote in message news:yzopesnnlgidhelsrrci forum.dlang.org...assert(foo(x));Having the compiler see inside function bodies is problematic.
Feb 03 2014
Daniel Murphy:Why do you need that? You can tell that foo() is not strongly pure from its signature. That's enough. Bye, bearophileassert(foo(x));Having the compiler see inside function bodies is problematic.
Feb 03 2014
"bearophile" wrote in message news:qfqkkpkdialejlknrpyx forum.dlang.org...Why do you need that? You can tell that foo() is not strongly pure from its signature. That's enough.Enough to tell it _might_ have a side effect, not enough to know it _will_. The number of false positives would make it near useless.
Feb 03 2014
Daniel Murphy:Enough to tell it _might_ have a side effect, not enough to know it _will_. The number of false positives would make it near useless.How many impure functions do you call in your asserts? In D we have a purity system, and now it works well enough. It's a good idea to actually start use it, for asserts, contracts, parallelism, etc. Bye, bearophile
Feb 03 2014
On 3 February 2014 17:00, bearophile <bearophileHUGS lycos.com> wrote:Daniel Murphy:Rephrase to 'How many *functions* do you call in your asserts?' If a function has a side effect (or returns), I'd have thought that typically people want to store that value first, then test it using assert(). Regards Iain.Enough to tell it _might_ have a side effect, not enough to know it _will_. The number of false positives would make it near useless.How many impure functions do you call in your asserts?
Feb 03 2014
"bearophile" wrote in message news:aifyouczfuqhdgubpfsw forum.dlang.org...How many impure functions do you call in your asserts? In D we have a purity system, and now it works well enough. It's a good idea to actually start use it, for asserts, contracts, parallelism, etc.Do you really want to force all codebases to 'pure'ify all their functions? A function call in an assert might be a red flag, but it certainly isn't a bug.
Feb 03 2014
Daniel Murphy:Do you really want to force all codebases to 'pure'ify all their functions?What percentage of your functions are transitively called in your asserts? In my code it's a small percentage.A function call in an assert might be a red flag, but it certainly isn't a bug.I agree. I am suggesting to disallow just impure functions in asserts. We have an acceptably good type system, but are we afraid of using it? Bye, bearophile
Feb 03 2014
I have one semi-large code base where I validate the locking semantics by adding assert(!lock.try_acquire)'s. That's clearly a side effect, but also clearly should never have one if the code is correct. On 2/3/14, 10:20 AM, bearophile wrote:Daniel Murphy:Do you really want to force all codebases to 'pure'ify all their functions?What percentage of your functions are transitively called in your asserts? In my code it's a small percentage.A function call in an assert might be a red flag, but it certainly isn't a bug.I agree. I am suggesting to disallow just impure functions in asserts. We have an acceptably good type system, but are we afraid of using it? Bye, bearophile
Feb 03 2014
Brad Roberts:I have one semi-large code base where I validate the locking semantics by adding assert(!lock.try_acquire)'s. That's clearly a side effect, but also clearly should never have one if the code is correct.I see, and you can't you use a special library-defined assert for that purpose. Bye, bearophile
Feb 03 2014
Am Mon, 03 Feb 2014 10:33:11 -0800 schrieb Brad Roberts <braddr puremagic.com>:I have one semi-large code base where I validate the locking semantics by adding assert(!lock.try_acquire)'s. That's clearly a side effect, but also clearly should never have one if the code is correct.Damn those gotchas. Basically lock.try_acquire is pure when it returns false, and if not, the program is terminated anyways so it doesn't make a difference. I also noticed that contracts don't work at all with shared objects. Where you synchronize around a mutex inside a method you have to move all checks into the critical section. Yeah, its obvious, but when you turn a non-thread-safe structure into a thread-safe one and have to delete all in-out-blocks it hurts a bit. :) -- Marco
Feb 03 2014
Marco Leise:Damn those gotchas. Basically lock.try_acquire is pure when it returns false, and if not, the program is terminated anyways so it doesn't make a difference.So an annotation like the proposed noreturn (similar to GCC function annotation, and useful for functions that do not return, so they can be used where you use assert(0) and the like) is not enough to solve this problem. Bye, bearophile
Feb 03 2014
If someone implements this test, we could see how many problems it causes in Phobos (and eventually in the D front-end) and perhaps even see if it finds some problem. Bye, bearophile
Feb 03 2014
On Monday, 3 February 2014 at 14:57:19 UTC, bearophile wrote:Two simple examples of code that is meant to be forbidden: int foo(ref int y) pure nothrow { return y++; } void main() { int x; assert(++x); assert(foo(x)); } Bye, bearophileAren't these things you might do inside a unittest?
Feb 03 2014
Jesse Phillips:Aren't these things you might do inside a unittest?Mutating state and calling impure functions is OK in an unittest. So this code is OK: int foo(ref int y) pure nothrow { return y++; } unittest { int x; ++x; assert(x); foo(x); assert(x); } Bye, bearophile
Feb 03 2014
An example of the problem? http://forum.dlang.org/thread/52EFE127.8070504 yahoo.com?page=2#post-xodootdnxopfyeqmhnjb:40forum.dlang.org Bye, bearophile
Feb 04 2014
Am Tue, 04 Feb 2014 14:25:14 +0000 schrieb "bearophile" <bearophileHUGS lycos.com>:An example of the problem? http://forum.dlang.org/thread/52EFE127.8070504 yahoo.com?page=2#post-xodootdnxopfyeqmhnjb:40forum.dlang.org Bye, bearophileYes, this is definitely why asserts should not have side effects when they succeed. I think maybe the earlier try_lock example could be written more cleanly as: assert(lock.is_locked); Still this requires is_locked to be "strongly pure", which cannot be expressed explicitly in D. (Otherwise it could change the implicit this and cause a side-effect.) -- Marco
Feb 04 2014
Marco Leise:Yes, this is definitely why asserts should not have side effects when they succeed.Can't you define a impureAssert() in Phobos and use it for the few cases when you need it, and use a pure-only assert() for all other cases? Bye, bearophile
Feb 04 2014
Am Tue, 04 Feb 2014 22:38:43 +0000 schrieb "bearophile" <bearophileHUGS lycos.com>:Marco Leise:What would happen to them in release compiles? -- MarcoYes, this is definitely why asserts should not have side effects when they succeed.Can't you define a impureAssert() in Phobos and use it for the few cases when you need it, and use a pure-only assert() for all other cases? Bye, bearophile
Feb 04 2014
Marco Leise:What would happen to them in release compiles?Perhaps their body that calls the lazy argument should be wrapped in version(assert) {} else {...}. Bye, bearophile
Feb 04 2014
"Marco Leise" wrote in message news:20140204184527.296f64e5 marco-leise.homedns.org...Still this requires is_locked to be "strongly pure", which cannot be expressed explicitly in D. (Otherwise it could change the implicit this and cause a side-effect.)Actually it only requires const-pure to prevent side effects.
Feb 04 2014