extension to scope

Frits van Bommel fvbommel at REMwOVExCAPSs.nl
Sun Jan 28 03:12:16 PST 2007


Alex Burton wrote:
> I would like to say that the ability to declare a class reference as scope, which guarantees that the destructor is called when exceptions occur, is a great feature that allows much more elegant code than putting try catches every where.
> 
> However I think that it is somewhat limited in that references to other objects held by the class are not guaranteed to be freed.
> 
> I would like to see the scope keyword's meaning extended so that any objects referenced by the scoped class are freed if no other references to them exist, and that this is done recursively.

The "if no other references exist" part can be a bit hard to determine 
without running a full GC cycle or some tricky analysis by the compiler.

> This would allow the logical use of scope beyond simple little convienience classes to large transaction type objects which need to be rolled back when an exception occurs.
> 
> This is of great importance to me when I have classes representing a transaction that may use some real resources such as files, ports etc.

If you ensure that no other references exist, you can just tell the 
members to clean up after themselves and then delete them. See the 
modifications I made to your code:

> Using an example I would like the code below to output 
> ~C
> ~B
> ~A
> finished
> 
> import std.stdio;
> 
> class A
> {
> 	~this() { writefln("~A"); }		
> };
> 
> class B
> {
> 	A a;
replace with:
	private A a; // to make sure no other references exist

	/// Call this to clean up before deleting instances of
	/// this class, to clean up resources.
	void close() { delete a; }

> 	this() { a = new A(); }	
> 	~this() { writefln("~B"); }		
> };
> 
> class C
replace that line with:
scope class C	// to make sure it never gets deleted by the GC

> {
> 	B b;
	private B b;	// to make sure no other references exist

> 	this() { b = new B(); }
> 	~this() { writefln("~C"); }		

Because of the 'scope' at the start of the class declaration, it is now 
safe to reference member objects in the destructor. (That's undefined 
behavior when it's called by the GC, but scoped classes don't get 
deleted by the GC) So replace destructor with:
  	~this() { b.close; delete b; writefln("~C"); }

> };
> 
> int main()
> {
> 	{
> 		scope auto x = new C;
> 	}
> 	writefln("finished");
> 	return 0;
> }

You *could* do all the deletions in the destructors, but then you need 
to make damn sure your objects won't _ever_ be deleted by the GC.


P.S.
Ideally, of course, you'd be allowed to declare members as 'scope', so 
that they always get deleted when the referencing object is. 
Unfortunately, this is not currently allowed.
(A way to implement this would be to 'inline' scoped members)



More information about the Digitalmars-d mailing list