Please Note: This question is about the difference in terminology between the words "destructor" and "finalizer" and their correct usage. I have merely provided examples of their use in C# and C++/CLI to demonstrate why I am asking the question. I am well aware of how it is implemented in both C# and the CLR, but I am asking about the correct use of terminology.
In the C# world the terms "destructor" and "finalizer" seem to be used pretty much interchangeably, which I suspect is because the C# specification describes the non-deterministic cleanup functionality using the word "destructor", whereas the CLR documentation always uses the word "finalizer", so within the realms of C# they mean the same thing.
However, in the C++/CLI specification there is a distinction made between the two. It allows both deterministic and non-deterministic cleanup, and uses the term "destructor" for the deterministic functionality and "finalizer" for the non-deterministic functionality:
The finalizer provides non-deterministic cleanup. A finalizer is a "last-chance" function that is executed during garbage collection, typically on an object whose destructor was not executed.
Additionally the Wikipedia descriptions of destructor and finalizer indicate that destructors and finalizers are separate concepts, and supports the C++/CLI spec's use of the terms with regard to determinism:
Unlike destructors, finalizers are not deterministic. A destructor is run when the program explicitly frees an object. A finalizer, by contrast, is executed when the internal garbage collection system frees the object.
The questions:
Is there, from a computer science point of view, a clearly defined difference between a "destructor" and a "finalizer", or is the terminology something that can only be defined contextually?
If there is a clearly defined difference, then why would the C# spec use the 'wrong' terminology?
Finalizers (historically referred to as destructors) are used to perform any necessary final clean-up when a class instance is being collected by the garbage collector. In most cases, you can avoid writing a finalizer by using the System.
Destructor implicitly calls the Finalize method, they are technically the same.
A finalizer is called when an object is garbage collected – after an object has become garbage (unreachable), but before its memory is deallocated. Finalization occurs non-deterministically, at the discretion of the garbage collector, and might never occur.
Finalize is similar to traditional C++ destructors, as each is responsible for freeing object resources. C++ destructors are executed immediately when an object goes out of scope, whereas finalize is called during object cleanup at GC. In C#, finalize cannot be directly called or overridden.
1) Is there a well-defined difference between "destructor" and "finalizer" as used in industry or academia?
There certainly appears to be. The difference seems to be that destructors are cleanup methods that are invoked deterministically, whereas finalizers run when the garbage collector tells them to.
2) In that case, the C# spec gets it wrong -- finalizers are called "destructors" in C#. Why did the authors of the C# spec get it wrong?
I don't know, but I can guess. In fact, I have two guesses.
Guess #1 is that on May 12th, 1999 there was not a wikipedia article clearly describing the subtle difference between these two concepts. That's because there wasn't a wikipedia. Remember back when there wasn't a wikipedia? Dark ages, man. The error might simply have been an honest mistake, believing that the two terms were identical.
Heck, for all I know, the two terms were identical on May 12th, 1999, and the difference in definitions only evolved later, as it became obvious that there was a need to disambiguate between eager and lazy cleanup methods.
Guess #2 is that on May 12th, 1999, the language design committee wished to leave open the possibility that a "destructor" could be implemented as something other than a finalizer. That is, the "destructor" was designed to be a C# language concept that did not necessarily map one-to-one with the .NET "finalizer" concept. When designing a language at the same time as the framework it sits atop is also being designed, sometimes you want to insulate yourself against late-breaking design changes in your subsystems.
The language committee's notes for May 12th 1999 read in part:
We're going to use the term "destructor" for the member which executes when an instance is reclaimed. Classes can have destructors; structs can't. Unlike in C++, a destructor cannot be called explicitly. Destruction is non-deterministic – you can't reliably know when the destructor will execute, except to say that it executes at some point after all references to the object have been released. The destructors in an inheritance chain are called in order, from most descendant to least descendant. There is no need (and no way) for the derived class to explicitly call the base destructor. The C# compiler compiles destructors to the appropriate CLR representation. For this version that probably means an instance finalizer that is distinguished in metadata. CLR may provide static finalizers in the future; we do not see any barrier to C# using static finalizers.
So, there, you now know everything I know on the subject. If you want to know more, ask Anders next time you see him.
Strictly speaking C# doesn't have a destructor (I believe the C# spec is confusing on this point). C#'s finalizer looks like a C++ destructor but, as you say, is non-deterministic. C# has deterministic clean-up in the form of IDisposable::Dispose
(but this is still not called a destructor).
C++/CLI has deterministic destructors, which look like C++ destructors. At the CLI level these map onto IDisposable::Dispose()
(IDisposable
is implemented for you ). C++/CLI has non-deterministic finalizers, which look like destructors but use the ! prefix instead of the ^ prefix.
The fact that C++/CLI uses the same syntax for destructors that C# uses for finalizers can be a little confusing - but it fits better with C++, which has a strong tradition of deterministic destruction.
Unfortunately the lack of universal definitions of these terms means you always need to clarify what you are talking about. Personally I always use the word finalizer when talking about the C# concept and reserve destructor for contexts where it definitely implies deterministic destruction.
[Update] Since my original post here Eric Lippert has posted his response (the accepted answer) and followed up with a blog post on the same. I'm glad to see we're in agreement :-)
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