Re: trick to make throwing method @nogc
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! solution 1/ === You can throw a static Exception. auto staticEx(string msg, string file = __FILE__, size_t line = __LINE__)() @nogc { immutable static Exception e = new Exception(msg, file, line); return e; } void main() @nogc { throw staticEx!"bla"; } not good for the call stack display, tho. solution 2/ === Throw an Error. Errors shouldn't be caugth and consequently they lead to program termination so you don't care about the leak. import std.experimental.allocator: make; import std.experimental.allocator.mallocator: Mallocator; void main() @nogc { throw make!Error(Mallocator.instance, "bla"); } good when errors are not designed to be caught. not good for exceptions because might leak to death depending on how the exceptions happens (i.e in a loop ouch). solution 3/ === Reference counting. Not explored so far. To finish, using a assert(0) is bad. assert(0) throws an error, it's really not like an Exception.
Re: trick to make throwing method @nogc
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! You can wrap a gc function in a nogc call using a function pointer that casts it to a nogc. You do this first by casting to void* then back to the same signature as the function + @nogc. This "tricks" the compiler in to calling the gc function from a nogc function. The problem is, of course, it is not safe if the gc is turned off as it will result in a memory leak. This may or may not be an issue with enforce depending on if it allocates before or after the check.
Re: trick to make throwing method @nogc
On Saturday, 25 February 2017 at 20:49:51 UTC, Adam D. Ruppe wrote: A wrapper that unifies these 4 steps like enforce is pretty easy to implement. yeah easy to use exception in @nogc as long as the catch knows to free it too. Alas, not my case. Exception can be catched not in my code.
Re: trick to make throwing method @nogc
On Saturday, 25 February 2017 at 20:49:51 UTC, Adam D. Ruppe wrote: On Saturday, 25 February 2017 at 20:40:26 UTC, Eugene Wissner wrote: it builds and doesn't throw if I compile with: dmd -release though it causes a segfault, what is probably a dmd bug. No, that's by design. assert(0) compiles to a segfault instruction with -release. A wrapper that unifies these 4 steps like enforce is pretty easy to implement. yeah easy to use exception in @nogc as long as the catch knows to free it too. But anyway segfault is not very descriptive :)
Re: trick to make throwing method @nogc
On Saturday, 25 February 2017 at 20:40:26 UTC, Eugene Wissner wrote: it builds and doesn't throw if I compile with: dmd -release though it causes a segfault, what is probably a dmd bug. No, that's by design. assert(0) compiles to a segfault instruction with -release. A wrapper that unifies these 4 steps like enforce is pretty easy to implement. yeah easy to use exception in @nogc as long as the catch knows to free it too.
Re: trick to make throwing method @nogc
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.
Re: trick to make throwing method @nogc
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.
trick to make throwing method @nogc
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!