What’s the difference between a destructor and a finalizer?


Today, another dialogue, and another episode of my ongoing series “what’s the difference?”

What’s the difference, if any, between a “destructor” and a “finalizer”?

Both are mechanisms for cleaning up a resource when it is no longer in use. When I was asked this, at first I didn’t think there was a difference. But some Wikipedia searches turned up a difference; the term “destructor” is typically used to mean a deterministically-invoked cleanup, whereas a “finalizer” runs when the garbage collector says to run it.

Doesn’t that mean that the C# spec uses the term “destructor” incorrectly?

Yes, by these definitions, the C# spec gets it wrong. What we call a “destructor” in the spec is actually a finalizer, and what we call the “Dispose()” method invoked by a “using” statement is in fact a “destructor”.

The CLI spec calls the finalizer by its right name.

Why did the authors of the C# spec get it wrong?

I don’t know, but I can guess. 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/deterministic and lazy/nondeterministic cleanup methods. Anyone who has more historical perspective on this than I do, feel free to chime in here.

Guess #2 is that on May 12th, 1999, the language design committee wished to leave open the possibility that a C# “destructor” could be implemented as something other than a CLR finalizer. That is, the “destructor” was designed to be a C# language concept that did not necessarily map one-to-one with the CLR’s “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. Deliberately preventing name conflation is one way to do that.

What’s your sudden obsession with May 12th, 1999 about?

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. 

Notice that this supports my hypothesis that the language design team was attempting to insulate themselves from becoming tied to a particular CLR term.

Comments (20)

  1. Pavel Minaev says:

    Guess #3: first a decision was made to use the C++ ~ClassName() syntax for it (likely for the same reasons why colon is used for base class list etc), and then it was called "destructor" because that’s what a thing that looks like that is called in C++.

  2. Jon Skeet says:

    "The C# spec" isn’t an unambiguous term either, of course… there’s the Microsoft version and the ECMA version. ECMA-334 (4th edition) has this to say in section 17.12:

    [Note: In the previous version of this standard, what is now referred to as a "finalizer" was called a

    "destructor". Experience has shown that the term "destructor" caused confusion and often resulted to

    incorrect expectations, especially to programmers knowing C++. In C++, a destructor is called in a

    determinate manner, whereas, in C#, a finalizer is not. To get determinate behavior from C#, one should use

    Dispose. end note]

    Further points of confusion I’ve noted in the past: due every value type have a parameterless constructor or not? It does according to C#, but not according to the CLI spec. Then there’s the concept of a static constructor, which doesn’t exist in the CLI – the distinction that C# makes between a type with a static constructor and one with only static variable initializers is only present in terms of the beforefieldinitflag (AFAIK).

    It’s a good job this doesn’t impact on regular developers most of the time :)

  3. zoldello says:

    It is interesting that you are concerned about the historical reason why something is wrong in Software Engineering. I personally consider the "historically why" irrelevant when it comes to Software. All that matters is what is correct so you can do my job well. No one will pay you on a job to tell them why var is not a keyword as some author implicitly imply. However, many will pay you to use it in your code.

  4. In my opinion, the choice of "~ClassName" as the _finalizer_ syntax is single worst mistake in the design of C#. It needlessly confuses people.

    C++/CLI has a very elegant solution: a new syntax ("!ClassName" ) for a new concept.

  5. @Zoldello:

    Understanding the historical perspective may not be very important for fixing today’s problem. But it is QUITE important for making sure that we don’t repeat the mistakes of the past.

    Now, I’m not sure that Eric is going to be designing a new language anytime soon. But I certainly hope that anyone who *is* planning to design a new language is reading Eric’s blog because of wonderful little tidbits like this that help elucidate the pitfalls and details that are important for an undertaking as difficult as language (and compiler) design.

  6. Chris Shepley says:

    It is called a destructor because syntactically, that is what it is in a c-style language.  Whether or not c# has deterministic finalization is another thing entirely.  The using pattern merely mimics the behavior of  deterministic desctruction and relies on proper implementation to ensure that later finalization attempts are suppressed.

  7. Pavel Minaev says:

    > due every value type have a parameterless constructor or not? It does according to C#, but not according to the CLI spec.

    There’s no contradiction here, since two concepts need not map one-to-one. So every value type has a parameterless public constructor in C#, but such a constructor needs not be represented by a constructor on IL level.

  8. Jon Skeet says:

    @Pavel: I agree that the two concepts don’t *have* to map… it’s just surprising when they don’t.

  9. AJ.NET says:

    I remember that the issue of determinsitic vs. non-deterministic destruction caused quite a few of the more heated discussions back in late 2000/early 2001, when .NET was still beta.

    See http://groups.google.de/group/microsoft.public.dotnet.languages.csharp/browse_thread/thread/55053af9d6ffaac4/6cf64cc6affd0778?hl=de&q=c%23+destructor+finalizer+%22alexander+jung%22 for example, with Eric Gunnerson among the participants :-D

    Eventually those discussions lead to the introduction of the disposable pattern (but we never got determinsitic destruction).

    Anyway, back then most developers looking into C# had C++ background, and where certainly alienated by this semantic change (especially since it invalidated a lot of idioms we were used to). However I’m a little surprised that this is even an issue today, a decade later…

  10. Its my pet peeve with C#, that C++ style destructors have gone and we have to use the using keyword to get the same automatic disposal.

    My big wish for the next version of C# is that if a struct implements IDisposable (or a new similar interface) and is used as a local variable, an automatic using block is inserted reaching to the end of that variable’s scope.

    To make it work, we would need copy constructors to be called when one is used as a value parameter and insert calls to .Dispose before an over-writing assignment or being passed into an out parameter. Basically do what C++ does.

    You are the C# wish fairy, aren’t you? I also want a pony.

  11. Tanveer Badar says:

    "Yes, by these definitions, the C# spec gets it wrong. What we call a “destructor” in the spec is actually a finalizer, and what we call the “Dispose()” method invoked by a “using” statement is in fact a “destructor”. "

    Wrong actually. Destructor, as in C++, is always called except for pathological conditions like throwing exceptions from one destructor when unwinding is already in progress etc. ‘using( )’ on the other hand is entirely optional in C#. Best a compiler can do is generate a warning, or some some tool like FxCop yell at you that you forgot to dispose a disposable object.

    If C# wants to promote using( ) as a true destructor best approach would be to do what C++/CLI did. Reference types with stack allocated syntax and calling Dispose automatically upon exiting lexical scope if the type implements IDisposable.

  12. Motti says:

    If value types were allowed to have destructors they could be deterministic and improve the language considerably (IMHO).

    http://stackoverflow.com/questions/173670/why-is-there-no-raii-in-net

  13. Gabe says:

    Motti: what sort of value types would use destructors anyway? I don’t think I’ve ever seen one.

  14. Lord Dust says:

    @zoldello

    *You* may not get paid for those things, but examining previously-made decisions in language design and observing the impact they have had on users is, in fact, one of the things *Eric* gets paid for. Why would it surprise you to know that Eric puts some thought into it?

    In addition, as a programmer, knowing the reasoning behind certain idioms, concepts, and so forth helps determine their advantages and disadvantages in practice. To pick a grand and well-worked over example, we use OOP because historically, straight-up procedural programming had several disadvantages when used in the large. Ignoring the why of this tends to lead to things like Eric’s oft-mentioned "object happiness", or difficult-to-maintain procedural programming in disguise.

  15. Gabe says:

    Come to think of it, isn’t having destructors useless without being able to override the assignment (=) operator? I think it’s a really messy way to avoid some using()s or Dispose() calls.

  16. dskcheck says:

    is there any link that the language commette notes are actually recorded on May 12th of 1999. Please share the link.

  17. @Tanveer Badar who said:

    "Wrong actually. Destructor, as in C++, is always called except for pathological conditions like throwing exceptions from one destructor when unwinding is already in progress etc. ‘using( )’ on the other hand is entirely optional in C#."

    You’ve got your analogy between C++ and C# wired up wrongly, so steady on with the "wrong actually"!

    This is how to request automatic deterministic destruction in C#. The first line enables it, the second does not:

    using (var aCSharpVar = new ACSharpClass()) { .. scope… }

    var aCSharpVar = new ACSharpClass();

    And this is how to make the same distinction in C++:

    ACppClass aCppVar;

    ACppClass *aCppPtr = new ACppClass();

    In other words, it is optional in BOTH languages. The entire subject of "exception safety" in C++ exists only because the second option is always available. If you make the wrong choice, destructors are NOT automatically called during stack unwind.

    The only difference is that each language makes a different choice for which should be the most succinct and readable – the one it expects its users to most frequently use. And that in turn is influenced by the assumed presence/absence of an asynchronous GC.

    So on the "consumer" side of automatic cleanup, the only difference is a matter of emphasis. The capabilities are identical.

    The "implementation" side is another matter – I would love to see language support in C# for implementing IDisposable, such that specific fields in a class can be marked as "ownership" relationships, i.e. the boilerplate of Dispose would get written automatically as in C++/CLI. The use of special language syntax for finalizers in C# does in retrospect seem like a strange choice, because now the general advice is that we almost never need to write a finalizer – they are a highly specialized, advanced and error-prone area. And yet implementing IDisposable is very common (turns out that memory is not the only resource!) and involves much tedious boilerplate in a big containment/inheritance hierarchy. So language support for implementing IDisposable would make a lot more sense than language support for writing finalizers.

    @Gabe – "Come to think of it, isn’t having destructors useless without being able to override the assignment (=) operator?"

    On value types, pretty much, because value types get copied when they are assigned. As in C++, if you need a special destructor, you’d need a special assignment/copy-constructor.

    On reference types, there’s no such issue. Destructors (Dispose) are extremely useful and assignment is only a problem because it allows us to accidentally lose track of an object without disposing it. But we have ‘readonly’ to help there.

    Suppose the keyword ‘using’ was overloaded (again) to become a new modifier on field declarations:

    class A { using B _myB = new B(); }

    This would fail to compile if B did not implement IDisposable. It basically would cause A to implement IDisposable by forwarding Dispose on to _myB.

    Now, the fact that we can assign a new object to _myB creates a "hole" into which undisposed B instances might fall, but we can avoid that in a simple way by also marking the field as readonly:

    class A { using readonly B _myB = new B(); }

    That says that an A has a single associated B whose lifetime is bounded by the lifetime of the A. This could also allow the compiler/CLR to optimise by nesting the B instance inside the storage of the A, reducing the number of separate objects visible to the GC.

  18. Xarx says:

    There’s more fundamental distinction between destructors and finalizers (than whether they are called deteministically).

    Imagine you want to implement a “proper” garbage collection (GC) mechanism in C++. C++ has destructors. (When you delete an object, it’s destructor gets called.) The question is: Can the GC reuse the C++ destructors for finalizers? The answer is: No, it can’t, it wouldn’t work.

    The reason is in that destructors assume that objects are COMPLETE at the time of destruction, e.g. all member pointers point to live objects. When you delete an object, it’s destructor is called first, and only then the destructors of child objects are called. The destruction order is completely under control of the programmer.

    On the other hand, when GC begins to delete objects, the deletion is performed in random order. At the time when an object is being finalized, its child objects might already have been finalized.

    Thus, changing memory management method from e.g. reference counting to mark-and-sweep garbage collection cannot be transparent, you’d have to rewrite the destructors in order to work in the GC environment. (And when changing back to reference counting, you’d have to rewrite them again. They cannot be written so that they work under both memory management methods.) That’s why destructors and finalizers are in fact completely different types of methods.

    BTW, this may also explain why in managed C++ the syntax “~X()” is a shortcut for the Dispose method, not for the finalizer.

  19. Xarx, you are WRONG in your post:

    “BTW, this may also explain why in C# the syntax “~X()” is a shortcut for the Dispose method, not for the finalizer.”

    “~X()” is the C# styntax for implementing the FINALIZER.

    http://msdn.microsoft.com/en-us/library/system.object.finalize.aspx

    Destructors are the C# mechanism for performing cleanup operations. Destructors provide appropriate safeguards, such as automatically calling the base type’s destructor. In C# code, Object..::.Finalize cannot be called or overridden.

    I think Xarx just made a typo. I think Xarx meant to say “in C++ the syntax”. I’ll fix it. — Eric

  20. Hi Eric!

    One idea for "What’s the difference between"-series:

    Reflection (& attributes) vs expression trees

    Both are metaprogramming ways to manipulate "code as data"-structures..