According to the documentation, a class destructor is "expected to
release any resources held by the object."[1] However, if resources to
be released are in objects to be garbage collected, "those references
are no longer valid."[1]
How is a class supposed to release something for which it no longer has
a valid reference?
Bradley
[1] http://www.digitalmars.com/d/class.html#destructors.

According to the documentation, a class destructor is "expected to
release any resources held by the object."[1] However, if resources to
be released are in objects to be garbage collected, "those references
are no longer valid."[1]
How is a class supposed to release something for which it no longer has
a valid reference?
Bradley
[1] http://www.digitalmars.com/d/class.html#destructors.

Yeah, that's a good one :)
Tango has a good resolution for this, that stemmed from long discussion
on the NG. Those changes never made it into phobos, IIRC

According to the documentation, a class destructor is "expected to
release any resources held by the object."[1] However, if resources to
be released are in objects to be garbage collected, "those references
are no longer valid."[1]
How is a class supposed to release something for which it no longer
has a valid reference?
Bradley
[1] http://www.digitalmars.com/d/class.html#destructors.

Yeah, that's a good one :)
Tango has a good resolution for this, that stemmed from long discussion
on the NG. Those changes never made it into phobos, IIRC

Isn't the destructor behavior dictated by the language? How can it be
fixed with a library? Replace or bypass the GC?
Thanks,
Bradley

According to the documentation, a class destructor is "expected to
release any resources held by the object."[1] However, if resources
to be released are in objects to be garbage collected, "those
references are no longer valid."[1]
How is a class supposed to release something for which it no longer
has a valid reference?
[1] http://www.digitalmars.com/d/class.html#destructors.

Yeah, that's a good one :)
Tango has a good resolution for this, that stemmed from long
discussion on the NG. Those changes never made it into phobos, IIRC

Isn't the destructor behavior dictated by the language? How can it be
fixed with a library? Replace or bypass the GC?

*Behavior* is dictated by the language, yes. But the *order* in which
they're invoked is determined by the library (specifically, the GC) and
the program (if 'delete' is used). So yes, this may be fixable by
replacing the GC.

According to the documentation, a class destructor is "expected to
release any resources held by the object."[1] However, if resources
to be released are in objects to be garbage collected, "those
references are no longer valid."[1]
How is a class supposed to release something for which it no longer
has a valid reference?
Bradley
[1] http://www.digitalmars.com/d/class.html#destructors.

Yeah, that's a good one :)
Tango has a good resolution for this, that stemmed from long
discussion on the NG. Those changes never made it into phobos, IIRC

Isn't the destructor behavior dictated by the language? How can it be
fixed with a library? Replace or bypass the GC?

According to the documentation, a class destructor is "expected to release
any resources held by the object."[1] However, if resources to be released
are in objects to be garbage collected, "those references are no longer
valid."[1]
How is a class supposed to release something for which it no longer has a
valid reference?

Huuaaaahhh!
I remember someone suggesting that 'scope' be a valid modifier for class
instance variables, and it'd basically mean "when this class gets destroyed,
destroy this other instance as well." Like auto-deletion when you use a
scope reference in a function:
class ResourceHolder
{
scope SomeResource mRsrc;
this(char[] name)
{
mRsrc = new SomeResource(name);
}
}
..
{
scope holder = new ResourceHolder("a.file");
...
} // holder is destroyed here, and so is its mRsrc member.
Another solution would be to change the behavior of the GC so that deletion
on program end _is_ deterministic. That is, it'd basically run a collection
sweep, call finalizers on objects which don't have references to them, and
keep doing that until nothing is left. That way, references to other
classes would always be valid in destructors, since the GC wouldn't collect
those references until everything that points to them is destroyed.

According to the documentation, a class destructor is "expected to release
any resources held by the object."[1] However, if resources to be released
are in objects to be garbage collected, "those references are no longer
valid."[1]
How is a class supposed to release something for which it no longer has a
valid reference?

Huuaaaahhh!
I remember someone suggesting that 'scope' be a valid modifier for class
instance variables, and it'd basically mean "when this class gets destroyed,
destroy this other instance as well." Like auto-deletion when you use a
scope reference in a function:

Is scope a valid modifier for a data member? The documentation states
"scope cannot be applied to globals, statics, data members, inout or out
parameters".[2] In my tests, using scope on a data member compiles, but
doesn't change the behavior.

class ResourceHolder
{
scope SomeResource mRsrc;
this(char[] name)
{
mRsrc = new SomeResource(name);
}
}
..
{
scope holder = new ResourceHolder("a.file");
...
} // holder is destroyed here, and so is its mRsrc member.
Another solution would be to change the behavior of the GC so that deletion
on program end _is_ deterministic. That is, it'd basically run a collection
sweep, call finalizers on objects which don't have references to them, and
keep doing that until nothing is left. That way, references to other
classes would always be valid in destructors, since the GC wouldn't collect
those references until everything that points to them is destroyed.

I remember someone suggesting that 'scope' be a valid modifier for
class instance variables, and it'd basically mean "when this class
gets destroyed, destroy this other instance as well." Like
auto-deletion when you use a scope reference in a function:

Is scope a valid modifier for a data member?

No, that paragraph was about a suggestion that it *should* be :).

Another solution would be to change the behavior of the GC so that
deletion on program end _is_ deterministic. That is, it'd basically
run a collection sweep, call finalizers on objects which don't have
references to them, and keep doing that until nothing is left. That
way, references to other classes would always be valid in destructors,
since the GC wouldn't collect those references until everything that
points to them is destroyed.

Are you saying that a proper class destructor can't be written without
modifying the language?

I think he's saying that it can be fixed by modifying the GC (which
isn't so much part of the language as it is of the standard library).

Some cases like closing a socket or a file opened with the unix open(2)
are not affected, because the file is identified with an integer, which
is stored in your class -- you can safely close it.
But, even if the object is a heap object, there exists a fairly simple
way to do this *without* modifying the GC algorithms. You can delay the
destruction until the next GC cycle using a global table -- in the
example below, the Foo object is never deleted until it is removed from
the global table, which is done from the destructor, *after* the cleanup
is done.
Notes:
1. Don't do this for a linked list's next pointer or similar, or you
will only remove one linked list element per GC run.
2. Look out for cycles -- this is essentially a reference counting
technique, so cyclical data structures will never be claimed.
3. Don't reorder the lines marked A and B, or use a 'delete f' in the
destructor because those actions are not safe if the GC runs while your
destructor is running -- this could happen if this object is manually
deleted or declared with scope, etc.
class Foo {
// must be called
cleanup();
}
class Bar {
static bool[Foo] pity_the_foo;
Foo f;
this()
{
f = new Foo;
pity_the_foo[f] = true;
}
~this()
{
f.cleanup(); // A
pity_the_foo.remove(f); // B
// delete f; -- Don't do this
}
}
Kevin

How is a class supposed to release something for which it no longer has a
valid reference?

Jarrett Billingsley wrote:

I remember someone suggesting that 'scope' be a valid modifier for class
instance variables, and it'd basically mean "when this class gets destroyed,
destroy this other instance as well." Like auto-deletion when you use a
scope reference in a function:
class ResourceHolder
{
scope SomeResource mRsrc;
this(char[] name)
{
mRsrc = new SomeResource(name);
}
}
..
{
scope holder = new ResourceHolder("a.file");
...
} // holder is destroyed here, and so is its mRsrc member.
Another solution would be to change the behavior of the GC so that deletion
on program end _is_ deterministic. That is, it'd basically run a collection
sweep, call finalizers on objects which don't have references to them, and
keep doing that until nothing is left. That way, references to other
classes would always be valid in destructors, since the GC wouldn't collect
those references until everything that points to them is destroyed.

Hmm, I think I've run into this problem just a few days ago, as my own
(very basic) LinkedList implementation was getting a little bit heavy on
the GC. So, I thought I might be able to make it a little bit quicker by
adding a destructor and deleting the Nodes that point to the actual data
(the Nodes that the LinkedList has created). But suddenly I wasn't able
to iterate through the Nodes while in the destructor, and so, I wasn't
able to delete them. I'm not really sure if the GC is causing the one
second pauses that I get when I'm on a really heavy load doing thousands
of LinkedLists and releasing them. Maybe I should try using pure D
dynamic arrays instead of my own container... Or try Tango when it's
released. Do the dynamic arrays in D, or the Tango containers use GC?
And about the scope keyword on a class member suggestion: What about the
"auto" keyword. What's the difference between the auto and the scope
keywords?
class Any
{
auto SomeOther m_someOther;
this()
{
m_someOther = new SomeOther();
}
~this()
{
//automatically deletes m_someOther...
}
}

And about the scope keyword on a class member suggestion: What about the
"auto" keyword. What's the difference between the auto and the scope
keywords?

"scope" is for automatic deletion. "auto" is for type inference.
"auto" used to also be for automatic deletion, but its dual purpose was
annoying, especially when you wanted to have both of its meanings apply
(which wasn't possible).
"auto" may still do automatic deletion when a type is also supplied, I'm
not sure, but if so that's just for backwards compatibility. Don't use
it for that in new code.

No ;)
'auto' is the default (hidden) storage class for local variables in a
function. So the following declarations are equivalent:
int x;
auto int x;
'auto' is in the same family as 'static', 'const', and 'scope'. 'auto' does
not do type inference. Type inference is triggered when there is a storage
class, but no type. So these all trigger type inference:
auto x = 5;
static y = 10;
const z = 15;
scope f = new Foo();
'auto' just happens to be the most common of the bunch, and so you see it a
lot more. But it doesn't mean "infer the type."

"auto" may still do automatic deletion when a type is also supplied, I'm
not sure, but if so that's just for backwards compatibility. Don't use it
for that in new code.

No ;)
'auto' is the default (hidden) storage class for local variables in a
function. So the following declarations are equivalent:
int x;
auto int x;
'auto' is in the same family as 'static', 'const', and 'scope'. 'auto' does
not do type inference. Type inference is triggered when there is a storage
class, but no type. So these all trigger type inference:
auto x = 5;
static y = 10;
const z = 15;
scope f = new Foo();
'auto' just happens to be the most common of the bunch, and so you see it a
lot more. But it doesn't mean "infer the type."

Right, forgot about all that for a moment[1]. However, that is how it
*should* be. And if you follow those rules, it works just fine, so...
[1] Which is weird, since the code I'm currently working on uses 'const'
for type inference wherever possible ;)

And about the scope keyword on a class member suggestion: What about
the "auto" keyword. What's the difference between the auto and the
scope keywords?

"scope" is for automatic deletion. "auto" is for type inference.
"auto" used to also be for automatic deletion, but its dual purpose was
annoying, especially when you wanted to have both of its meanings apply
(which wasn't possible).
"auto" may still do automatic deletion when a type is also supplied, I'm
not sure, but if so that's just for backwards compatibility. Don't use
it for that in new code.

Ahh, thanks for clearing that up. I changed all the auto-keywords in my
own projects code to scope. There were some 50 of them. I'm not sure. It
looked like it had some effect on my program, so maybe the auto keyword
doesn't even work for it's old purpose anymore? Don't know. But thanks,
now I only have my destructors unfunctional.

And about the scope keyword on a class member suggestion: What about
the "auto" keyword. What's the difference between the auto and the
scope keywords?

"scope" is for automatic deletion. "auto" is for type inference.
"auto" used to also be for automatic deletion, but its dual purpose
was annoying, especially when you wanted to have both of its meanings
apply (which wasn't possible).
"auto" may still do automatic deletion when a type is also supplied,
I'm not sure, but if so that's just for backwards compatibility. Don't
use it for that in new code.

Ahh, thanks for clearing that up. I changed all the auto-keywords in my
own projects code to scope. There were some 50 of them. I'm not sure. It
looked like it had some effect on my program, so maybe the auto keyword
doesn't even work for it's old purpose anymore? Don't know. But thanks,
now I only have my destructors unfunctional.

Well, one way to make sure a class never gets GC'ed is to make it a
'scope class'. Then you can only keep references as scope variables, and
they always get explicitly deleted. The only problem is that you're then
not allowed to keep them in member variables, just function-local vars.