The difference between a destructor and a finalizer?
Asked Answered
G

4

41

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?

Grimonia answered 9/12, 2009 at 9:40 Comment(0)
G
43

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.

Graveclothes answered 9/12, 2009 at 16:40 Comment(1)
Interesting; from the notes it certainly sounds like at the time destructor did not imply determinism so I reckon you're probably right that it's a distinction that has evolved since.Grimonia
D
7

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 :-)

Diaconate answered 9/12, 2009 at 9:48 Comment(7)
The 'problem' is that C# does call it a destructor.Frontality
Yes, I recalled that after I first answered - it uses both terms - hence my added comment about it being confusing. It's both clearer and still correct to call them finalizers.Diaconate
+1 I think this is the best answer. Looks like the C# spec is a bit misleading with its terms. Maybe it was written by an intern :PGuadalupeguadeloupe
In the C# 3.5 definition, there is no use of the word 'finalizer' -- just the word 'destructor', which is defined as "a member that implements the actions required to destruct an instance of a class" C# does have destructors, and not finalizers. It's the CLR that has finalizers.Winne
@Steve You are correct that the C# spec refers to the language feature as a destructor, which implements the finalizer concept. I still say this is confusing.Diaconate
Then I suggest never calling C#'s finalizers "destructors" and you will never have the confusion.Forefinger
@sixlettervariables - agreed :-)Diaconate
W
4

I believe 'destructor' is the C# code, and the 'finalizer' is the compiled CIL method. The C# compiler turns a destructor into a finalizer.

EDIT: To be more verbose; The C# language specification defines a 'destructor' as a C# instance method on a class. 'destructor', then, is part of the C# grammar -- destructors are a linguistic object appearing in source code.

A destructor is a member that implements the actions required to destruct an instance of a class. Destructors cannot have parameters, they cannot have accessibility modifiers, and they cannot be invoked explicitly. The destructor for an instance is invoked automatically during garbage collection.

A 'finalizer' is a term used in the Common Language Runtime, for example in calls to GC.WaitForPendingFinalizers(), and it refers to any .net language, not just C#. Any .net reference type can have a finalizer. For a C# class (the source code artifact), the destructor compiles into the CIL method which is the CLR type's finalizer.

Or more succinctly, destructor is to finalizer as source code is to machine code ;)

Winne answered 9/12, 2009 at 9:43 Comment(9)
I know they map to the same thing. I was asking about the correct use of terminology.Grimonia
Hi, Greg. I wasn't talking about them mapping to the same thing; where there is a what I meant was that one term refers to a source code artefact, and the other refers to the compiled machine-code artefact. Destructors are mentioned in the C# language spec and are part of the C# grammar; Finalizers are not. However, garbage collection (which is language agnostic) refers to finalizers; eg, in calls like GC.WaitForPendingFinalizers(); thus, Finalizer is a CLR term, and refers to the process of cleaning up before releasing memory of a .net object. I'll try to edit my post to clarify it there, tooWinne
C# does not have destructors, only finalizers. The fact that it shares a similar syntax to C++'s destructor does not matter.Forefinger
We're probably violently agreeing here. C#'s destructors don't do what C++'s destructors do. They aren't the same thing. But the spec defines the word 'destructor' in the context of the C# language, so it certainly has them. They just have nothing to do with the C++ concept.Winne
@sixlettervariables: The portion of a C# program enclosed in braces following ~ClassName is a destructor. If a class has a destructor, the C# compiler will auto-generate a finalizer which contains the destructor code plus some boilerplate. The boilerplate code seems to have been designed by people who had no clue what the IDisposable pattern was going to look like (it may well predate the IDisposable pattern), but since code appears in the finalizer that does not appear in the destructor, the terms are not quite synonymous.Banana
@supercat: back in '09 I did not realize they had screwed up the spec by conflating the finalizer by calling it a destructor. My bad. If you would like behavior which matches a 'destructor' then do not use a C# finalizer. My original statement should be amended to read, "C# does not have true destructors, instead relying on the finalizer pattern. The fact that they borrowed the term from C++ does not change its non-determinism."Forefinger
@sixlettervariables: Destructors are to my mind one of the silliest features of C#. Had all the compiler logic related to Finalize been omitted, programs could still have define finalizers perfectly well. Given that a program can almost never use C# destructors correctly without using GC.SuppressFinalize() and occasionally GC.KeepAlive(), eliminating programs' dependency on the name of the Finalize method doesn't really help portability. All it does is add confusion.Banana
@supercat: That is probably where you're going wrong: You should not write applications which rely on or call finalizers. All you have to do is properly use IDisposable and you have no problems. Finalizers are a fallback for poor programming practices.Forefinger
@sixlettervariables: That's my point; C# destructors (the things that start with ~ClassName) are a first-class language feature, but IDisposable is an afterthought. C# would be a better language IMHO if the compiler knew nothing of Finalize, even if such support was replaced with nothing. Had the effort that went into wrapping destructors with try/finally blocks instead been put into allowing classes to indicate which fields they own, and automating Dispose-based cleanup thereof, it would be better still.Banana
R
3

If we abide to the "deterministic" definition of destructors, then I would say that in .NET objects have no destructors unless explicitly implemented by using the IDisposable interface.

Rutabaga answered 9/12, 2009 at 9:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.