Tom Hollander's blog

patterns, practices and pontification

Constructors and Inheritance – Why is this still so painful?

Constructors and Inheritance – Why is this still so painful?

  • Comments 19

Recently my team discovered a limitation in the RelativeDateTimeValidator that ships with the Enterprise Library Validation Application Block. This validator is used to check if a DateTime object occurs within a configured time before or after Now. It’s a useful validator for checking things like birth dates and expiry dates. However we discovered that it assumes the date being validated is in local time – if the date is specified in UTC (which we do in our app) the calculation will be wrong. Fixing the logic was no big deal – it just involved checking if the DateTimeKind is UTC and if so, converting it to a local time before doing the validation. However like many people we didn’t want to modify the original EntLib codebase, so instead I built a new class imaginatively titled RelativeDateTimeValidatorEx that inherits from RelativeDateTimeValidator and corrects this problem. But while the important code change was only a couple of lines, I was forced to manually implement every one of the 14 constructors from the base class (with no code beyond calling each base constructor) to ensure equivalent and compatible functionality. In my case I didn’t need to change the public interface at all. But even in the (probably more common) case where a derived class includes new functionality that warrants new constructors, it’s very common to want to include all of the base class’s original constructors as well.

To provide a quick example (but thankfully with fewer constructors), imagine the following base class:

public class BaseClass
{
    public BaseClass(int a) : this(a, "Foo")
    {
    }
    public BaseClass(int a, string b) : this(a, b, DateTime.Now)
    {
    }
    public BaseClass(int a, DateTime c) : this(a, "Foo", c)
    {
    }
    public BaseClass(int a, string b, DateTime c)
    {
        // Shared initialisation code
    }
}

Now if I want to build a new class that provides equivalent functionality and supports a new optional parameter, I’m left with this at a minimum:

public class DerivedClass : BaseClass
{
    public DerivedClass(int a) : base(a)
    {
    }
    public DerivedClass(int a, string b) : base(a, b)
    {
    }
    public DerivedClass(int a, DateTime c) : base(a, b, c)
    {
    }
    public DerivedClass(int a, string b, DateTime c) : base(a, b, c)
    {
    }
    public DerivedClass(int a, string b, DateTime c, long d) : base(a, b, c)
    {
        // New initialisation code
    }
}

…and if I want to offer more permutations, the number of constructors may grow exponentially.

The good news is that C# 4.0 will finally include support for optional parameters (a very useful feature that VB programmers have enjoyed for years), which will partly mitigate this issue by providing an alternative to writing a crap-load of constructors. However even with optional parameters, it would be nice if you could tell C# that you want your derived class to inherit all of the base class’s constructors.

On a somewhat related note, it’s often bothered me that there is no way to include constructors as a mandatory part of a class’s contract. This comes up every time you use a plug-in pattern where you create instances of a class at runtime using Activator.CreateInstance and you require all of your plug-ins to be initialised with the same information. The most logical approach is to require each plug-in to implement the same constructor. While you can make this work by passing the constructor parameters to Activator.CreateInstance, this is completely untypesafe as the compiler can’t enforce that all your plug-ins have the required signature (this is a common problem for people implementing custom EntLib plug-ins that receive their configuration properties via a NameValueCollection passed to the constructor. People who forget (or don’t know) to implement this constructor often have a hard time figuring out what is wrong).

The other approach you sometimes see is to create the instances using a default (parameterless) constructor and set the initialisation parameters through a public interface method like Initialize(NameValueCollection properties). But this approach has its own downsides. First, it means your plug-in classes are most likely constructed in an unusable state. Second, it still suffers from the same type safety problems, as there is no guarantee that every plug-in class implements a parameterless constructor.

So why isn’t it possible to specify constructors as a part of a class (or interface) contract? And to make it useful, there should be a compiler-verifiable way to create instances of unknown types that call the said constructor. I’m no language designer, but I’m thinking of something like this:

public class PlugIn
{
    public virtual PlugIn(NameValueCollection properties)
    {
    }
}
// Create an instance
Type plugInType = Type.GetType(plugInTypeNameFromConfigFile);
NameValueCollection properties = LoadPropertiesFromConfigFile();
PlugIn myConcretePlugIn = Plugin.New(plugInType, properties); // Compiler-checked

This is probably a bastardisation of the virtual keyword but you get the idea. Another benefit of this approach is that you could safely new-up instances of generic types in a lot more situations. Currently you can specify a where T : new() constraint for a generic parameter that specifies that the generic type must have a default constructor. I’ve often thought this was overly restrictive, and that it should be possible to do something like where T : new(int, string). This may still be desirable, but if constructors could be specified as a part of a construct then the type alone could allow the code to create new instances. For example, if you had a generic parameter T where T : PlugIn then your code could safely execute T myPlugIn = new T(properties).

Anyway, end of rant. I’m interested in hearing whether any other programming languages have either of the features I’ve proposed, or if there are any good reasons I haven’t thought of which would make these features undesirable or impossible.

  • Even I can't comment much on why language doesn't support it, but agree that this is a pain today

  • "Virtual constructors" are perfectly valid and have been done already (in Delphi). What's more, there's a production-quality commercial .NET language that supports it today - Delphi Prism (aka RemObjects Oxygene). It's actually more than that - they have proper metaclasses, which allows for virtual static members as well! Have a look:

    http://prismwiki.codegear.com/en/Class_References

    The "correct" (i.e. typesafe) way to do the same in C# would be to use the factory pattern: you use Activator.CreateInstance() to create an instance of a factory class (and there you demand a no-arg constructor via template parameter constraints), and then you use a method to create the actual object. That way, you avoid the created-but-uninitialized state for plugin objects.

    But yeah, I wish we could do in C# what we can in Oxygene/Prism....

  • http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2540.htm

    C++ is adding this as well.

  • Tom Hollander recently posted about a change he required to the Enterprise Library for date/time validation

  • Have wanted this for years!

    While you're at it... what about abstract static methods!

  • Have 1 ctor with all parameters, and create a builder and/or factory to support your special needs. A bonus is that the builder and factory methods are named, so that it actualy makes sense what new Bar(1, DateTime.Now, 12, 7) means.

  • I'm not meaning to sound like I'm preaching or anything, so don't take this the wrong way. I suspect that there are a couple reasons for this:

    1) Class object hierarchies are built from the base down, right? So, class B inherits from A, and in the process of creating a B, you get an A first, right? After checking it, yes, that's right. The virtual keyword guarantees that the dynamic type's method is called when the base class' method is used in the code. This means that in order to implement this, the compiler must guarantee that base.Ctor is called whenever derived.Ctor is called. . .and not only that, it must be called BEFORE the derived.Ctor is even called, in order to conform to specification. Using virtual is probably not the right way to go, is what I'm saying. I would think a word like "chains" is more appropriate, or something.

    2) It goes against object-oriented design to use inheritance in this way. What you're saying is that a base class should be able to tell a derived class how to build itself. This goes against every encapsulation and inheritance rule there is. Furthermore, if you wanted to program against an interface, how would an interface provide a ctor? Just give the signature? Sure, that's not difficult syntactically, but again, there's something very fishy smelling about an interface telling anyone who implements it how they are allowed to be constructed. It's true that there's methods on interfaces that are like, "void Initialize(XmlNode node);". I never liked those either, and I wish there were some way around this, but I don't see a good way to implement it, and I don't like the idea of virtual ctors.

    Having said all that, even not liking virtual ctors, I certainly agree that programming plugins would be considerably easier with that technique. I've been trying to come up with better for a while now, and have come up empty-handed so far.

  • I think that there's nothing wrong with being able to require a specific constructor signature in an interface. After all, it's just a contract - if it covers post-initialization operations, why can't it cover initialization itself (and yes, we can do it with factories - but those are just a hack; delegates and events made publisher/subscriber pattern virtually transparent in C#, and there's no reason not to do the same for abstract factory pattern as well).

  • Interesting post.. I cant help but wonder, although I totally get your point about constructor "interfaces".. Why not just hide the constructor and create a "Build" method in an interface?

    interface IInitableFromSomeParams

    {

      void Build(SomeParams params);

    }

    class MyClass : IInitableFromSomeParams

    {

    private MyClass() {}

    public void Build(SomeParams params)

    }

    SomeMethod()

    {

    MyClass o = new MyClass();

    o.Build(myParams);

    }

    Same effect? What benefit do you really have from making the constructor actually a constructor?

    Could be me being naive, but I just dont see the benefit? You would have less constructors you need to implement, you can mix and match between instantiation logic (meaning you have type-safe parameter classes) so you would actually have a much more flexible codebase?

  • Woops, just thought, there is not even a need to hide the constructor.. Sorry, not had morning coffee yet!

  • Rob - The approach you've listed is useed a lot, but I already listed two limitations with it in my post (assuming we don't know at compile time what the concrete type is):

    1. We can't be sure it has a default constructor

    2. The class can't be sure it's been initialised properly, since the initialisation call is separate to the constructor.

  • I think you're looking at contracts the wrong way.

    There's a great tradition of separating usage of a class and construction of a class (see the discussion on the factory patterns in the GoF book for more on this) Think of interfaces more as a contract for the consumer of a class than the implementer of it. A consumer of a class shouldn't be depending on a way to construct a class so the contract doesn't include that. This is basic separation of concerns. If construction of a class is complex enough to warrant it's own contract it's probably complex enough to warrant it's own abstract factory. You can then create an interface on that factory.

  • Mendelt - What you're saying is true much of the time. Normally when you construct an object you know exactly what type you are dealing with (even if you plan to use it polymorphically later), so having an arbitarary constructor isn't a problem.

    However when dealing with plug-ins, you need to polymorphically _create_ objects, not just use them. So when building a plug-in framework, it would be nice if you could make the constructor part of the contract of the base class. I'm definitely not advocating making this feature mandatory in all classes.

    BTW I assume you're just referring to my second proposal. My first proposal wasn't about making constructors part of a contract, it was just about making it easier for an inherited class to reuse all of its base class's constructors if it so chooses.

    Tom

  • Tom listed,

    "2. The class can't be sure it's been initialised properly, since the initialisation call is separate to the constructor."

    By the way, I view this as slightly wrong. The use of the call to initialize is for the person writing the framework (or whatever it is). In other words, you CreateInstance on the type, and then immediately call Initialize on it - you don't hope that they do.

    Now, if you're saying that it may be the case that the person who implemented your interface and added their Initialize method did not write the Initialize method correctly, then that's their fault, not yours. I wouldn't agonize over that.

  • After reflecting on this more, I realized that having a virtual ctor does not solve the problem you brought up in number 2, Tom.

    Namely, if you cannot be guaranteed that an object is properly initialized after you call the virtual Initialize method, then what guarantee do you have that they implemented their ctor properly so as to initialize their object correctly? True, if you had a virtual ctor, then you could at least be guaranteed that YOUR ctor would be called at some point (as long as you make sure that the keyword virtual on a ctor doesn't actually mean virtual, because that would require the derived types to call base.Ctor, again), but this does not in any way imply that the object is constructed properly - there could have been many other pieces of data that it needed because it's the concrete type and not your abstract type.

    I'm not sure that this is really all that important. Since .NET can handle the situation you're talking about by having a separate initialization method (or what not), including the possibility of some kind of virtual ctor seems like overkill. I like your idea of having T : new(params) a lot, though. I had actually tried that when I was more naive, because I thought, "Why would that NOT work?" But it didn't, of course. In any case, I think I've come up with a temporary solution to the problem. I will be posting it on my blog tonight or tomorrow morning, after I have had a little time to work it all out. It's only temporary because it will only work at run-time, not compile-time, and I'd like to solve this problem for compile-time. If we had template-metaprogramming as C++ does, we could use a compile-time assertion and (I believe) be guaranteed that they have the proper ctors defined for you to use, but we don't, so my solution is only a run-time solution. I'll come back and let you know when I post, if you'd like.

Page 1 of 2 (19 items) 12