IanG on Tap

Ian Griffiths in Weblog Form (RSS 2.0)

Blog Navigation

April (2018)

(1 item)

August (2014)

(1 item)

July (2014)

(5 items)

April (2014)

(1 item)

March (2014)

(1 item)

January (2014)

(2 items)

November (2013)

(2 items)

July (2013)

(4 items)

April (2013)

(1 item)

February (2013)

(6 items)

September (2011)

(2 items)

November (2010)

(4 items)

September (2010)

(1 item)

August (2010)

(4 items)

July (2010)

(2 items)

September (2009)

(1 item)

June (2009)

(1 item)

April (2009)

(1 item)

November (2008)

(1 item)

October (2008)

(1 item)

September (2008)

(1 item)

July (2008)

(1 item)

June (2008)

(1 item)

May (2008)

(2 items)

April (2008)

(2 items)

March (2008)

(5 items)

January (2008)

(3 items)

December (2007)

(1 item)

November (2007)

(1 item)

October (2007)

(1 item)

September (2007)

(3 items)

August (2007)

(1 item)

July (2007)

(1 item)

June (2007)

(2 items)

May (2007)

(8 items)

April (2007)

(2 items)

March (2007)

(7 items)

February (2007)

(2 items)

January (2007)

(2 items)

November (2006)

(1 item)

October (2006)

(2 items)

September (2006)

(1 item)

June (2006)

(2 items)

May (2006)

(4 items)

April (2006)

(1 item)

March (2006)

(5 items)

January (2006)

(1 item)

December (2005)

(3 items)

November (2005)

(2 items)

October (2005)

(2 items)

September (2005)

(8 items)

August (2005)

(7 items)

June (2005)

(3 items)

May (2005)

(7 items)

April (2005)

(6 items)

March (2005)

(1 item)

February (2005)

(2 items)

January (2005)

(5 items)

December (2004)

(5 items)

November (2004)

(7 items)

October (2004)

(3 items)

September (2004)

(7 items)

August (2004)

(16 items)

July (2004)

(10 items)

June (2004)

(27 items)

May (2004)

(15 items)

April (2004)

(15 items)

March (2004)

(13 items)

February (2004)

(16 items)

January (2004)

(15 items)

Blog Home

RSS 2.0

Writing

Programming C# 5.0

Programming WPF

Other Sites

Interact Software

Repeat After Me: C# Destructors Are NOT Like C++ Destructors

Thursday 12 August, 2004, 10:11 PM

I really wish C# destructors weren't called 'destructors'.

I really wish C# destructors didn't use the same syntax as C++ destructors.

Brad Abrams posts a question about the calling of virtual functions during the execution of a destructor. In case you're reading this in an aggregator while offline (e.g. on a train on your way to work; hi Benjamin!) here's the relevant code sample:

public class Base
{
    public virtual void DoCleanUp() 
    {
        Console.WriteLine("Do Base's Cleanup");
    }
    ~Base()
    {
        DoCleanUp();
    }
}

public class Derived : Base
{
    public override void DoCleanUp()
    {
        Console.WriteLine("Do Derived Cleanup");
    }
    ~Derived()
    {
        DoCleanUp();
    }
}

The question is: when an instance of Derived gets finalized, what gets printed out?

The first person to answer in Brad's comments got the answer right, by the way. But far more entertaining was an answer that came later. Someone called Mark H posted the wrong answer, but that wasn't the fun one. It was the followup from someone called Robert Kozak:

Looks like some people are confused on this issue.

I agree with Mark H. As soon as I saw it I knew that the output would be

[...repeats the wrong answer given by Mark H...]

It's not the getting it wrong that I found amusing, it was the fact that he was so condescending towards the people who actually got the answer right.

I also knew what the answer was as soon as I saw it, but unlike Mark H and Robert Kozak I took the all-important step of checking that I was right by actually running the code before posting. :-)

But the interesting thing is why Mark H is wrong. He presents a clear, logical and well argued case for why he thinks his answer is right, it just happens that he's wrong. And the reason he is wrong is because he thinks that a C# destructor will do the same thing as a C++ destructor. That's a reasonable assumption since they have identical syntax. Wrong, but reasonable nonetheless. Had the example been C++, he would have been correct, but C# behaves differently.

The fact is that C# destructors are not the same kind of thing at all as C++ destructors. For example, in C++, when an object is destructed, the notional type of the object changes during destruction, meaning when you invoke a virtual function from a destructor in a base class, then even if the derived type overrides the method, it won't invoke the overridden function, because once the base class destructor is entered, the object is no longer considered to be of the derived type. So this C++:

class Base
{
public:
    virtual void DoCleanUp()
    {
        Console::WriteLine("Do Base's Cleanup");
    }
    ~Base()
    {
        DoCleanUp();
    }
};

class Derived : public Base
{
public:
    void DoCleanUp()
    {
        Console::WriteLine("Do Derived Cleanup");
    }
    ~Derived()
    {
        DoCleanUp();
    }
};

will behave exactly as Mark H describes, unlike the C# version. (Note that although the above is managed C++, the classes I've defined here are not managed classes. If they were marked as __gc I think the behaviour would be different - the behaviour would then be the same as the C# code.)

This difference in behaviour is one of the reasons I think it's unhelpful that C# chooses to call what is really a finalizer a 'destructor'. The fact that it uses the C++ destructor syntax is equally unhelpful.

Then again, constructors behave differently too... Presumably Mark and Robert are also unaware that C# has different behaviour from C++ during construction:

public class Base
{
    public virtual void DoStartup() 
    {
        Console.WriteLine("Do Base's Startup");
    }
    public Base()
    {
        DoStartup();
    }
}

public class Derived : Base
{
    public override void DoStartup()
    {
        Console.WriteLine("Do Derived Startup");
    }
    public Derived()
    {
        DoStartup();
    }
}

The output of this is:

Do Derived Startup
Do Derived Startup

whereas in the equivalent C++ the result would have been:

Do Base's Startup
Do Derived Startup

(Brad's previous post on this topic covered this very issue. I'm guessing Mark and Robert didn't see that one...)

Seen in this light, at least it becomes clear that the behaviour of virtual functions in destruction is consistent with their behaviour during construction. But even so I still wish C# called destructors something else for anotherr reason: the perennial bugbear that they don't run deterministically. Making them look like C++ destructors (which do run deterministically) is just a recipe for confusion.

Copyright © 2002-2024, Interact Software Ltd. Content by Ian Griffiths. Please direct all Web site inquiries to webmaster@interact-sw.co.uk