Re: trick to make throwing method @nogc

2017-02-26 Thread Guest via Digitalmars-d-learn

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

2017-02-25 Thread Profile Anaysis via Digitalmars-d-learn

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

2017-02-25 Thread ikod via Digitalmars-d-learn
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

2017-02-25 Thread Eugene Wissner via Digitalmars-d-learn
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

2017-02-25 Thread Adam D. Ruppe via Digitalmars-d-learn
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

2017-02-25 Thread Eugene Wissner via Digitalmars-d-learn

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

2017-02-25 Thread ikod via Digitalmars-d-learn

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

2017-02-25 Thread ikod via Digitalmars-d-learn

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!