Re: Best way to manage non-memory resources in current D, ex: database handles.

2017-03-09 Thread Kagamin via Digitalmars-d-learn

RefCounted is ok


If GC methods it calls are legal during collection.


Re: Best way to manage non-memory resources in current D, ex: database handles.

2017-03-09 Thread Kagamin via Digitalmars-d-learn
Unique is probably not good for database connection: you then 
can't have connection in two variables, also if it holds a 
reference to GC-allocated memory, it can't be put to GC-allocated 
memory, since when that GC-allocated memory is collected, Unique 
will try to destroy its possibly already freed object resulting 
in use after free. RefCounted is ok, it has calls to GC in order 
to be scanned for GC references, though destructors during 
collection are called in a different thread, so the counter can 
be decremented incorrectly. Phobos tends to have specialized 
types like File and RcString, but they have the same problem with 
reference counting during collections.


Re: Best way to manage non-memory resources in current D, ex: database handles.

2017-03-08 Thread Chad Joan via Digitalmars-d-learn

Awesome, thank you!

On Thursday, 9 March 2017 at 00:47:48 UTC, Adam D. Ruppe wrote:
Now, if you forget to scope(exit), it is OK, the garbage 
collector WILL get around to it eventually, and it is legal to 
work with C handles and functions from a destructor. It is only 
illegal to call D's garbage collector's functions or to 
reference memory managed by D's GC inside the destructor. C 
pointers are fine.


It's good to have this confirmed.  I'm always a bit trepidatious 
around destructors.


Oooh, and it looks like there is more information in the language 
spec about @disable on struct constructors and postblits now 
(compared to the previous time I tried to learn about that 
feature).  So between that and your example, I think I have a 
feel for how to use that.  Thanks.


Have a wonderful day!


Re: Best way to manage non-memory resources in current D, ex: database handles.

2017-03-08 Thread Adam D. Ruppe via Digitalmars-d-learn

On Wednesday, 8 March 2017 at 23:54:56 UTC, Chad Joan wrote:

What's the best way to implement such a range in current D?


I'd go with a struct with disabled copying and default 
construction, then make the destructor free it and the function 
that returns it populate it.


So basically Unique.

The destroy function doesn't mention what methods specifically 
will be executed on the target object, other than "destructor 
or finalizer".


It calls the `~this()` function, aka the destructor. It is just 
sometimes called a finalizer in other contexts too. Same thing, 
different name.



So I have similar questions about this as I did Unique: How 
does it "free" the resource T?  What method does it call to 
tell T to deallocate itself?


So it doesn't deallocate itself, but it can deallocate its 
members.


It calls ~this(); first, your destructor, and you can free its 
members with that. Then it calls `free()` on the outer object 
pointer itself.


So clean up the members in the destructor and you should be good. 
Basically the same deal as with Unique.



I'm leaning towards this methodology;


This is good, but it is easy to forget the scope(exit) too.

That said, this is how my database.d handles its connection 
classes. If your connection is a struct, using the destructor is 
better (your option #3), since it just does this automatically - 
a struct destructor (unless it is in a dynamic array or some 
other kind of pointer) is automatically called on scope exit.


Classes, though, do not get their dtors called then - they wait 
until they are GC'd - so scope(exit) does a good job with getting 
them cleaned up faster.



===  (3)  Put a deallocate() method; call it in ~this()



This is what my database.d does with the query results. The 
database connection class is polymorphic and thus doesn't work 
well as a struct, but the query result worked beautifully as a 
struct and the destructor handles it.


I also threw in `@disable this(this);` to ensure it isn't copied 
somewhere so I don't have to refcount it or anything annoying 
like that. On the other hand, I must consume the query in-place 
(or pass it by pointer to other functions being careful not to 
keep it after the outer function returns)... but that's what I 
want to do anyway.




So my code looks something like this:


class Database {
   this(string conn) {
this.handle = establish_connection(conn);
if(this.handle is null) throw new Exception();
   }

   ~this() {
close_connection(this.handle);
   }

   Result query(string sql, string[] args) {
 // hugely simplified
 auto q = prepare_query(sql);
 bind_args(q, args);

 // the Result is constructed here and only here
 return Result(execute_query(q));
   }
}

struct Result {
 // no business default constructing it ever
 @disable this();

 // forbid copying it. Instead, pass it by pointer
 // or just loop it in-place and copy the results
 // elsewhere for storage.
 @disable this(this);

 // private constructor since only the query
 // method above should be making these
 private this(c_query_handle handle) {
this.handle = handle;
 // do whatever other allocation needs
 // to be done via C functions
// 

popFront(); // prime the first result
 }

 ~this() {
 // destroy whatever C resources this holds
 destroy_query_handle(this.handle);
 }

 Row front() {
return makeDFriendly(this.current_row);
 }

 void popFront() {
this.current_row = fetch_next_row(this.handle);
 }

 bool empty() {
return has_more_rows(this.handle);
 }
}



Then use it like this:


void main() {
auto db = new Database("db=test");
scope(exit) .destroy(db);

foreach(row; db.query("select * from foo", null)) {
// work with row
}
}



Now, if you forget to scope(exit), it is OK, the garbage 
collector WILL get around to it eventually, and it is legal to 
work with C handles and functions from a destructor. It is only 
illegal to call D's garbage collector's functions or to reference 
memory managed by D's GC inside the destructor. C pointers are 
fine.


It is just nicer to close the connection at a more specified time.