On 02/28/2010 09:16 PM, Ellery Newcomer wrote:
Hello
The impetus:
I agree, except I more and more think that scope classes were a
mistake. Structs with destructors are a much better solution, and
wrapping a class inside a struct would give it RAII semantics.
The problem:
In designing a library (or rather touching up someone else's library), I
have a class (interface?) Foo, and it has a method close (actually
several methods). Almost invariably (although conceivably not always),
usage involves manipulating Foo, and then remembering to call close.
That last part is obnoxious.
One obtains a Foo from function foo.
What I'd like is for the result of foo to have RAII semantics by
default, with the possibility of nixing it if the user actually cares.
I want to take the burden of remembering that stupid close off the user.
For example:
void bar(){
auto a = foo();
a.doStuff();
}
has an implicit call to close after doStuff.
The impetus suggests I can do this by wrapping Foo inside a struct, but
I'm not so sure how well this would work out. Also note that close can
fail in a number of ways relating to file io.
So I wrote up a simple prototype.
Thoughts?
import std.stdio;
class Foo{
int k;
this(int i){
writefln("bin %d",k);
k = i;
}
void doStuff(){
writefln("do stuff %d",k);
}
void close(){
writefln("close %d",k);
}
}
struct RAII(T){
T b;
bool extracted = false;
alias b this;
this (T i){
assert(i !is null);
writeln("in");
b = i;
}
~this(){
writeln("~this");
if(!extracted) b.close();
}
T extract(){
assert(!extracted);
T t = b;
b = null;
extracted = true;
return t;
}
}
RAII!(Foo) foo(int i){
return RAII!(Foo)(new Foo(i));
}
void main(){
auto a = foo(1);
auto b = foo(2).extract();
a.doStuff();
b.doStuff();
}
Maybe something along the lines of this
struct RAII(T : Object){
T b;
alias b this;
void delegate(T) destroyer;
this (T i, void delegate(T) called_at_exit){
b = i;
destroyer = called_at_exit;
}
~this(){
if (b) destroyer(b);
}
T extract(){
T t = b;
b = null;
return t;
}
}
class Foo {
this() { }
void close() {
writeln("closed.");
}
}
RAII!Foo foo() {
return RAII!Foo(new Foo, (Foo f) {f.close;});
}
for a slightly more generalized RAII struct, which works on classes only.