On Saturday, 25 February 2017 at 20:02:56 UTC, ikod wrote:
On Saturday, 25 February 2017 at 19:59:29 UTC, ikod wrote:
Hello,

I have a method for range:

struct Range {
    immutable(ubyte[]) _buffer;
    size_t             _pos;

    @property void popFront() pure @safe {
enforce(_pos < _buffer.length, "popFront from empty buffer");
        _pos++;
    }
}

I'd like to have @nogc here, but I can't because enforce() is non-@nogc. I have a trick but not sure if it is valid, especially I don't know if optimization will preserve code, used for throwing:

import std.string;

struct Range {
    immutable(ubyte[]) _buffer;
    size_t  _pos;

    this(immutable(ubyte[]) s) {
        _buffer = s;
    }
    @property void popFront() pure @safe @nogc {
        if (_pos >= _buffer.length ) {
            auto _ = _buffer[$]; // throws RangeError
        }
        _pos++;
    }
}

void main() {
        auto r = Range("1".representation);
        r.popFront();
        r.popFront(); // throws
}

Is it ok to use it? Is there any better solution?

Thanks!

Found that I can use

    @property void popFront() pure @safe @nogc {
        if (_pos >= _buffer.length ) {
                        assert(0, "popFront for empty range");
        }
        _pos++;
    }

which is both descriptive and can't be optimized out.

I made a test:

void main()
{
  assert(0);
}

it builds and doesn't throw if I compile with:
dmd -release

though it causes a segfault, what is probably a dmd bug. So I suppose it can be optimized out. And it isn't very discriptive, you probably throws the same AssertError for all errors. You can throw in @nogc code, you only have to allocate the exception not on the GC heap and free it after catching. I'm writing myself a library that is complete @nogc and I use exceptions this way:
- Allocate the exception
- throw
- catch
- free

A wrapper that unifies these 4 steps like enforce is pretty easy to implement.

Reply via email to