Being primarily a C++ developer the absence of RAII (Resource Acquisition Is Initialization) in Java and .NET has always bothered me. The fact that the onus of cleaning up is moved from the class writer to its consumer (by means of try finally
or .NET's using
construct) seems to be markedly inferior.
I see why in Java there is no support for RAII since all objects are located on the heap and the garbage collector inherently doesn't support deterministic destruction, but in .NET with the introduction of value-types (struct
) we have the (seemingly) perfect candidate for RAII. A value type that's created on the stack has a well defined scope and C++ destructor semantics can be used. However the CLR does not permit a value-type to have a destructor.
My random searches found one argument that if a value-type is boxed it falls under the jurisdiction of the garbage collector and therefore its destruction becomes non-deterministic. I feel that this argument isn't strong enough, the benefits of RAII are big enough to say that a value-type with a destructor cannot be boxed (or used as a class member).
To cut a long story short my question is: are there any other reasons value types can not be used in order to introduce RAII to .NET? (or do you think my argument about RAII's obvious advantages are flawed?)
Edit: I must have not phrased the question clearly since the first four answers have missed the point. I know about Finalize
and its non-deterministic characteristics, I know about the using
construct and I feel these two options are inferior to RAII. using
is one more thing the consumer of a class must remember (how many people forgot to put a StreamReader
in a using
block?). My question is a philosophical one about the language design, why is it the way it is and can it be improved?
For instance with a generic deterministically destructible value-type I can make the using
and lock
keywords redundant (achievable by library classes):
public struct Disposer<T> where T : IDisposable { T val; public Disposer(T t) { val = t; } public T Value { get { return val; } } ~Disposer() // Currently illegal { if (val != default(T)) val.Dispose(); } }
I can't help but end with a apropos quotation which I once saw but can't currently find its origin.
You can take my deterministic destruction when my cold dead hand goes out of scope. --Anon
Resource Acquisition Is Initialization (RAII) is a design idea introduced in C++ by Bjarne Stroustrup for exception-safe resource management. Thanks to garbage collection Java doesn't have this feature, but we can implement something similar, using try-with-resources.
RAII avoids using objects in an invalid state. it already makes life easier before we even use the object. There are three error cases to handled: no file can be opened, only one file can be opened, both files can be opened but copying the files failed.
Excellent question and one that has bothered me greatly. It appears that the benefits of RAII are perceived very differently. In my experience with .NET, the lack of deterministic (or at least reliable) resource collection is one of the major drawbacks. In fact, .NET has forced me several times to employ whole architectures to deal with unmanaged resources that might (but might not) require explicit collecting. Which, of course, is a huge drawback because it makes the overall architecture more difficult and directs the client's attention away from the more central aspects.
A better title would be "Why is there no RAII in C#/VB". C++/CLI (The evolution of the abortion that was Managed C++) has RAII in the exact same sense as C++. It's all just syntax sugar for the same finalisation pattern that the rest of the CLI languages use (Destructors in managed objects for C++/CLI are effectively finalisers), but it is there.
You might like http://blogs.msdn.com/hsutter/archive/2004/07/31/203137.aspx
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With