Re: Range non-emptyness assertions and opIndex
On Friday, 1 July 2016 at 11:35:40 UTC, ag0aep6g wrote: Huh? Asserts are ignored with -release. The only exception is assert(false) which terminates the program immediately, even with -release. Aha, that's what I was testing against so therefore the confusion.
Re: Range non-emptyness assertions and opIndex
On Friday, 1 July 2016 at 10:35:04 UTC, Nordlöw wrote: I think this is a important issue since asserts are not optimized away in release mode and D is very much about performance. Asserts are removed in release mode, enforce isn't. Here's an example: = void main(string[] args) { assert(args.length >= 1); } = dmd testfile.d This calls the assert function as expected: = _Dmain: : 55 pushrbp 0001: 48 8B EC mov rbp,rsp 0004: 48 83 39 01cmp qword ptr [rcx],1 0008: 73 0E jae 0018 000A: B9 03 00 00 00 mov ecx,3 000F: 48 83 EC 20sub rsp,20h 0013: E8 00 00 00 00 call _D5test28__assertFiZv 0018: 31 C0 xor eax,eax 001A: 5D pop rbp 001B: C3 ret = Now compiling in release mode: dmd -release testfile.d No assert in sight: = _Dmain: : 55 pushrbp 0001: 48 8B EC mov rbp,rsp 0004: 31 C0 xor eax,eax 0006: 5D pop rbp 0007: C3 ret =
Re: Range non-emptyness assertions and opIndex
On 07/01/2016 12:35 PM, Nordlöw wrote: What's the preferred way of reacting to emptyness in the members front, back, popFront, popBack --- using assert, enforce, throw, or simply relying on range-checking in the _store? I think assert is the most common way of checking. Simply ignoring the possibility is also common, as it's considered a programming error to call front/popFront/etc on an empty range. For the same reason, throwing an exception (via throw or via enforce) is less common. Exceptions are more for input/environment errors, not so much for programming errors. And what about using debug assert() instead of assert() typically when `_store`s `opIndex` already performs range-checking? I think this is a important issue since asserts are not optimized away in release mode and D is very much about performance. Huh? Asserts are ignored with -release. The only exception is assert(false) which terminates the program immediately, even with -release. A little example program: void main() { import std.stdio; int x = 1; assert(x != 1); writeln("hi"); } When compiled without -release, the program throws an AssertError. With -release it prints "hi".
Range non-emptyness assertions and opIndex
If I have a typical range definition like the following struct Range { @safe pure @nogc: bool empty() const nothrow { return _i == _j; } size_t length() const nothrow { return _j - _i; } bool front() const { assert(!empty); // TODO use enforce when it's @nogc return _store[_i]; } bool back() const { assert(!empty); // TODO use enforce when it's @nogc return _store[_j - 1]; } void popFront() { assert(!empty); ++_i; } void popBack() { assert(!empty); ++_i; } private: BitSet _store; // copy of store size_t _i = 0; // iterator into _store size_t _j = _store.length; } What's the preferred way of reacting to emptyness in the members front, back, popFront, popBack --- using assert, enforce, throw, or simply relying on range-checking in the _store? And what about using debug assert() instead of assert() typically when `_store`s `opIndex` already performs range-checking? I think this is a important issue since asserts are not optimized away in release mode and D is very much about performance.