digitalmars.D - Asserts and side effects
- Lars T. Kyllingstad (15/15) Nov 30 2009 The following is a quote from a comment in the Reddit post about asserts...
- bearophile (7/9) Nov 30 2009 Only pure asserts?
- Lars T. Kyllingstad (5/10) Dec 01 2009 Like Denis said, pure is a bit too strict. One just wants to make sure
- Denis Koroskin (29/44) Nov 30 2009 Compiler must do full code flow analysis to do that:
- KennyTM~ (2/53) Nov 30 2009 Can you give an example which @hasNoSideEffects but not @pure?
- Denis Koroskin (33/99) Nov 30 2009 Sure:
- Don (3/113) Nov 30 2009 Interestingly, provided source code is available, the CTFE engine can
The following is a quote from a comment in the Reddit post about asserts that Walter just linked to: "Asserts are not without pitfalls, though. If you aren't careful, what to put in the asserts, the program could behave differently" A trivial example of this is: int i; write(i); assert (++i == 1); write(i); Normally, this program prints "01", but in release mode it prints "00". Asserts should never change the behaviour of a program, but currently it is up to the programmer to verify that this is in fact the case. Would it be possible (and desirable) for the D compiler to statically check that asserts have no side effects? -Lars
Nov 30 2009
Lars T. Kyllingstad:Would it be possible (and desirable) for the D compiler to statically check that asserts have no side effects?Only pure asserts? If you put: assert (++i == 1); Inside a function precondition, it gets removed in release mode. Bye, bearophile
Nov 30 2009
bearophile wrote:Lars T. Kyllingstad:Like Denis said, pure is a bit too strict. One just wants to make sure that the assert doesn't *change* any variables. It should be able to read them, otherwise there would be no point in it. -LarsWould it be possible (and desirable) for the D compiler to statically check that asserts have no side effects?Only pure asserts?
Dec 01 2009
On Mon, 30 Nov 2009 13:52:48 +0300, Lars T. Kyllingstad <public kyllingen.nospamnet> wrote:The following is a quote from a comment in the Reddit post about asserts that Walter just linked to: "Asserts are not without pitfalls, though. If you aren't careful, what to put in the asserts, the program could behave differently" A trivial example of this is: int i; write(i); assert (++i == 1); write(i); Normally, this program prints "01", but in release mode it prints "00". Asserts should never change the behaviour of a program, but currently it is up to the programmer to verify that this is in fact the case. Would it be possible (and desirable) for the D compiler to statically check that asserts have no side effects? -LarsCompiler must do full code flow analysis to do that: bool foo(); // no body or body is very complicated void main() { assert(foo()); // okay to call or not? } I believe this is doable with introduction of a new attribute - hasNoSideEffects (shorter name would be better) with the following rules: - hasNoSideEffects functions cannot modify variables outside of a function scope. It means that they can read globals, but can not get a non-const reference (or pointer) to them. - hasNoSideEffects can only call other hasNoSideEffects functions - Body of an assert check has a hasNoSideEffects attribute, and follows the same rules. pure is a subclass of hasNoSideEffects. hasNoSideEffects functions are also very useful for various performance optimizations. I think it is as valid attribute as pure (even though it might affect code generation outside of a function body due to open optimization opportunities). Perhaps pure semantics should be changed to hasNoSideEffects (i.e. allow non-invariant input arguments and allow accessing globals). It will lose a memoization ability, but to be honest I don't think memoization needs to be implemented based on pure attribute alone. For example, std.math.pow() is pure, but is it worth memoizing? I think it's programmer who should decide what functions are expensive enough to be memoized, and these should be marked as such explicitly ( memoizable, or something).
Nov 30 2009
On Nov 30, 09 19:15, Denis Koroskin wrote:On Mon, 30 Nov 2009 13:52:48 +0300, Lars T. Kyllingstad <public kyllingen.nospamnet> wrote:Can you give an example which hasNoSideEffects but not pure?The following is a quote from a comment in the Reddit post about asserts that Walter just linked to: "Asserts are not without pitfalls, though. If you aren't careful, what to put in the asserts, the program could behave differently" A trivial example of this is: int i; write(i); assert (++i == 1); write(i); Normally, this program prints "01", but in release mode it prints "00". Asserts should never change the behaviour of a program, but currently it is up to the programmer to verify that this is in fact the case. Would it be possible (and desirable) for the D compiler to statically check that asserts have no side effects? -LarsCompiler must do full code flow analysis to do that: bool foo(); // no body or body is very complicated void main() { assert(foo()); // okay to call or not? } I believe this is doable with introduction of a new attribute - hasNoSideEffects (shorter name would be better) with the following rules: - hasNoSideEffects functions cannot modify variables outside of a function scope. It means that they can read globals, but can not get a non-const reference (or pointer) to them. - hasNoSideEffects can only call other hasNoSideEffects functions - Body of an assert check has a hasNoSideEffects attribute, and follows the same rules. pure is a subclass of hasNoSideEffects. hasNoSideEffects functions are also very useful for various performance optimizations. I think it is as valid attribute as pure (even though it might affect code generation outside of a function body due to open optimization opportunities). Perhaps pure semantics should be changed to hasNoSideEffects (i.e. allow non-invariant input arguments and allow accessing globals). It will lose a memoization ability, but to be honest I don't think memoization needs to be implemented based on pure attribute alone. For example, std.math.pow() is pure, but is it worth memoizing? I think it's programmer who should decide what functions are expensive enough to be memoized, and these should be marked as such explicitly ( memoizable, or something).
Nov 30 2009
On Mon, 30 Nov 2009 15:46:45 +0300, KennyTM~ <kennytm gmail.com> wrote:On Nov 30, 09 19:15, Denis Koroskin wrote:Sure: // can't be pure because pure functions // accept only immutable args hasNoSideEffects int deref(int* ptr) { return *ptr; } class Array { hasNoSideEffects int length() const { return _array.length; } hasNoSideEffects ref T opIndex(size_t index) { return _array[index]; } private T[] _array; } Array!(int) array = ...; for (int i = 0; i < array.length(); ++i) { int v1 = array[i]; // int v2 = array[i]; int v3 = array[i]; } It the example above, array.length and i-th value are only evaluated once, because length and opIndex both have no side effects. BTW, any class invariant should also be marked as hasNoSideEffects implicitly and checked accordingly. I think pure attribute is too restrictive to be useful. I believe there are an order of magnitude more functions that could be marked as hasNoSideEffects than those that could be marked as pure.On Mon, 30 Nov 2009 13:52:48 +0300, Lars T. Kyllingstad <public kyllingen.nospamnet> wrote:Can you give an example which hasNoSideEffects but not pure?The following is a quote from a comment in the Reddit post about asserts that Walter just linked to: "Asserts are not without pitfalls, though. If you aren't careful, what to put in the asserts, the program could behave differently" A trivial example of this is: int i; write(i); assert (++i == 1); write(i); Normally, this program prints "01", but in release mode it prints "00". Asserts should never change the behaviour of a program, but currently it is up to the programmer to verify that this is in fact the case. Would it be possible (and desirable) for the D compiler to statically check that asserts have no side effects? -LarsCompiler must do full code flow analysis to do that: bool foo(); // no body or body is very complicated void main() { assert(foo()); // okay to call or not? } I believe this is doable with introduction of a new attribute - hasNoSideEffects (shorter name would be better) with the following rules: - hasNoSideEffects functions cannot modify variables outside of a function scope. It means that they can read globals, but can not get a non-const reference (or pointer) to them. - hasNoSideEffects can only call other hasNoSideEffects functions - Body of an assert check has a hasNoSideEffects attribute, and follows the same rules. pure is a subclass of hasNoSideEffects. hasNoSideEffects functions are also very useful for various performance optimizations. I think it is as valid attribute as pure (even though it might affect code generation outside of a function body due to open optimization opportunities). Perhaps pure semantics should be changed to hasNoSideEffects (i.e. allow non-invariant input arguments and allow accessing globals). It will lose a memoization ability, but to be honest I don't think memoization needs to be implemented based on pure attribute alone. For example, std.math.pow() is pure, but is it worth memoizing? I think it's programmer who should decide what functions are expensive enough to be memoized, and these should be marked as such explicitly ( memoizable, or something).
Nov 30 2009
Denis Koroskin wrote:On Mon, 30 Nov 2009 15:46:45 +0300, KennyTM~ <kennytm gmail.com> wrote:Interestingly, provided source code is available, the CTFE engine can execute hasNoSideEffects functions. It doesn't require 'pure'.On Nov 30, 09 19:15, Denis Koroskin wrote:Sure: // can't be pure because pure functions // accept only immutable args hasNoSideEffects int deref(int* ptr) { return *ptr; } class Array { hasNoSideEffects int length() const { return _array.length; } hasNoSideEffects ref T opIndex(size_t index) { return _array[index]; } private T[] _array; } Array!(int) array = ...; for (int i = 0; i < array.length(); ++i) { int v1 = array[i]; // int v2 = array[i]; int v3 = array[i]; } It the example above, array.length and i-th value are only evaluated once, because length and opIndex both have no side effects. BTW, any class invariant should also be marked as hasNoSideEffects implicitly and checked accordingly. I think pure attribute is too restrictive to be useful. I believe there are an order of magnitude more functions that could be marked as hasNoSideEffects than those that could be marked as pure.On Mon, 30 Nov 2009 13:52:48 +0300, Lars T. Kyllingstad <public kyllingen.nospamnet> wrote:Can you give an example which hasNoSideEffects but not pure?The following is a quote from a comment in the Reddit post about asserts that Walter just linked to: "Asserts are not without pitfalls, though. If you aren't careful, what to put in the asserts, the program could behave differently" A trivial example of this is: int i; write(i); assert (++i == 1); write(i); Normally, this program prints "01", but in release mode it prints "00". Asserts should never change the behaviour of a program, but currently it is up to the programmer to verify that this is in fact the case. Would it be possible (and desirable) for the D compiler to statically check that asserts have no side effects? -LarsCompiler must do full code flow analysis to do that: bool foo(); // no body or body is very complicated void main() { assert(foo()); // okay to call or not? } I believe this is doable with introduction of a new attribute - hasNoSideEffects (shorter name would be better) with the following rules: - hasNoSideEffects functions cannot modify variables outside of a function scope. It means that they can read globals, but can not get a non-const reference (or pointer) to them. - hasNoSideEffects can only call other hasNoSideEffects functions - Body of an assert check has a hasNoSideEffects attribute, and follows the same rules. pure is a subclass of hasNoSideEffects. hasNoSideEffects functions are also very useful for various performance optimizations. I think it is as valid attribute as pure (even though it might affect code generation outside of a function body due to open optimization opportunities). Perhaps pure semantics should be changed to hasNoSideEffects (i.e. allow non-invariant input arguments and allow accessing globals). It will lose a memoization ability, but to be honest I don't think memoization needs to be implemented based on pure attribute alone. For example, std.math.pow() is pure, but is it worth memoizing? I think it's programmer who should decide what functions are expensive enough to be memoized, and these should be marked as such explicitly ( memoizable, or something).
Nov 30 2009