2007-01-17

Calling base constructors in C#

I occasionally find it annoying that I cannot specify at which point in a class's constructor I wish to invoke the base constructor. Having C# always invoke it before any of the code in my descendant constructor is executed sometimes causes me problems.

Considering .NET is capable of calling the ancestor constructor at any point I wondered why C# wont allow it. I contacted Anders Hejlsberg and he was kind enough to reply, unfortunately he seems to have answered a question I didn't ask :-)

Anyway, I have been deleting some old emails today and I came across his response, which he gave me permission to publish:

The problem with Delphi's model (allowing constructors to be called on
an already constructed object) is that it makes it impossible to have
provably immutable objects. Immutability is an important concept because
it allows applications to hand objects to an external party without
first copying those objects and still have a guarantee that the objects
won't be modified. If constructors can be called on already constructed
objects it obviously isn't possible to make such guarantees. In Delphi's
case that may be ok since Delphi doesn't really make type safety
guarantees anyway (you can cast any object reference to a
pointer-to-something and start poking away), but .NET goes further with
type safety and this would be a big hole.

There, now get out of my head ;-)

Anders

6 comments:

Jacob Thurman said...

I see Anders' point, but I think he's solving a problem that doesn't need solving. Really, who, besides someone who is on Delphi day #2 and learning how to construct object in code, calls a constructor on an instance. You CAN do Button1.Create(Self), but nobody actually does that.

Peter Morris said...

The problem is that he is explaining how to solve a problem that is different to what I asked.

I didn't ask for named constructors, I asked for the ability to call a base constructor from any point within my constructor's code rather than always at the start.

Richard said...

What do you expect of a Dane?! (only kidding, Anders is a legend)

I was having the same problem. Read your post, scratched my head and came up with this:

class Dane
{
public Dane(string fullName)
{
this.FullName = fullName;
}
string FullName = "";
}

class Anders
{
public Anders(string fName, string lName) : base(ConcatName(fName, lName))
{
//blue blah
}

public static string ConcatName(string fName, string lName)
{
return "The Great Dane " + fName + lName;
}
}

Ofcourse the method called has to be static which may introduce futher complication, depending on your needs.

Hope it helps

Richard (hlanvill at gmail dot com)

Peter Morris said...

Richard, but when that method is virtual you run into trouble...

public class BaseObject
{
public BaseObject()
{
DoSomething();
}
protected void DoSomething()
{
}
}

public class NewObject : BaseObject
{
private Person Owner;
public NewObject() : base()
{
Owner = new Person();
}

protected override DoSomething()
{
Owner.DoSomething();
}
}

What would be better is this...

public NewObject()
{
Owner = new Person();
base();
}

.NET allows it, just not C#!

Mario said...

I had the same problem and sometimes is annoying not to have the hability to call the base constructor.

My solution is avoiding constructors :) and use static methods (that a call creators) or public methods that must always call after the "new" (that a call initiators). Of course, this is not the best solution.

I exacly don't see Anders point, but when they have arguments about the safety or because it breaks OO paradigm I fell uneasy. The designers of C# should realy have more confident on what programers can do ;)

Daniel said...

I'm a little late to the conversation, but seeing as my search lead me here, it may be worth updating.

This has always bothered me, too, but I usually find a way to make it work using abstract or virtual methods declared in the base class.

It's not nearly as flexible as being able to call a constructor at will, but Anders has a very valid point.

As an object consumer, I need to know that an object will provide a minimum level of service. The moment derived code is allowed to run before the constructor, I can throw my expectations out the window. The derived object could pass itself to me half-initialized, and I wouldn't be prepared for it, because object X is always supposed to be fully initialized. That's really just the tip of the iceberg, but the rest are mostly different flavors of the above.

As it stands, customization can be achieved using calls to an abstract member; however, their introduction into the base class ensures its consumers will be aware of it. It would still be possible to say, "If you account for this, this, and this, then these are your minimum expectations," and that confidence is what makes OO possible without a constant Aspirin IV drip.