digitalmars.D.learn - trick to make throwing method nogc
- ikod (36/36) Feb 25 2017 Hello,
- ikod (9/45) Feb 25 2017 Found that I can use
- Eugene Wissner (20/75) Feb 25 2017 I made a test:
- Adam D. Ruppe (6/11) Feb 25 2017 No, that's by design. assert(0) compiles to a segfault
- Eugene Wissner (3/14) Feb 25 2017 But anyway segfault is not very descriptive :)
- ikod (3/7) Feb 25 2017 Alas, not my case. Exception can be catched not in my code.
- Profile Anaysis (9/45) Feb 25 2017 You can wrap a gc function in a nogc call using a function
- Guest (33/69) Feb 26 2017 solution 1/
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!
Feb 25 2017
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.
Feb 25 2017
On Saturday, 25 February 2017 at 20:02:56 UTC, ikod wrote:On Saturday, 25 February 2017 at 19:59:29 UTC, ikod wrote: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.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.
Feb 25 2017
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.
Feb 25 2017
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:But anyway segfault is not very descriptive :)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.
Feb 25 2017
On Saturday, 25 February 2017 at 20:49:51 UTC, Adam D. Ruppe wrote:Alas, not my case. Exception can be catched not in my code.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.
Feb 25 2017
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.
Feb 25 2017
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.
Feb 26 2017