Calling constructors in arbitrary places

Calling constructors in arbitrary places

Rate This
  • Comments 28

C# lets you call another constructor from a given constructor, but only before the body of the calling constructor runs:

public C(int x) : this(x, null)
{
  // …
}
public C(int x, string y)
{
  // …
}

Why can you call another constructor at the beginning of a constructor block, but not at the end of the block, or in the middle of the block?

Well, let's break it down into two cases. (1) You're calling a "base" constructor, and (2) you're calling a "this" constructor.

For the "base" scenario, it's quite straightforward. You almost never want to call a base constructor after a derived constructor. That's an inversion of the normal dependency rules. Derived code should be able to depend on the base constructor having set up the "base" state of the object; the base constructor should never depend on the derived constructor having set up the derived state.

Suppose you're in the second case. The typical usage pattern for this scenario is to have a bunch of constructors that take different arguments and then all "feed" into one master constructor (often private) that does all the real work. Typically the public constructors have no bodies of their own, so there's no difference between calling the other constructor "before" or "after" the empty block.

Suppose you're in the second case and you are doing work in each constructor, and you want to call other constructors at some point other than the start of the current constructor.

In that scenario you can easily accomplish this by extracting the work done by the different constructors into methods, and then calling the methods in the constructors in whatever order you like. That is superior to inventing a syntax that allows you to call other constructors at arbitrary locations. There are a number of design principles that support this decision. Two are:

1) Having two ways to do the same thing creates confusion; it adds mental cost. We often have two ways of doing the same thing in C#, but in those situations we want the situation to "pay for itself" by having the two different ways of doing the thing each be compelling, interesting and powerful features that have clear pros and cons. (For example, "query comprehensions" vs "fluent queries" are two very different-looking ways of building a query.)  Having a way to call a constructor the way you'd call any other method seems like having two ways of doing something -- calling an initialization method -- but without a compelling or interesting "payoff". 

2) We'd have to add new language syntax to do it. New syntax comes at a very high cost; it's got to be designed, implemented, tested, documented -- those are our costs. But it comes at a higher cost to you because you have to learn what the syntax means, otherwise you cannot read or maintain other people's code.  That's another cost; again, we only take the huge expense of adding syntax if we feel that there is a clear, compelling, large benefit for our customers.  I don't see a huge benefit here.

In short, achieving the desired construction control flow is easy to do without adding the feature, and there's no compelling benefit to adding the feature. No new interesting representational power is added to the language.

  • The one situation where I've found this rule awkward is when:

    - I have to perform proessing on my arguments, and

    - I need to pass the result of that processing to my base, and also use it in my ctor

    Example:

    1. I have a constructor whose ctor takes in a XamlReader, which is a streaming (forward-only) interface.

    2. I need to deserialize the XAML, and pass the result to my base ctor

    3. But I also need to buffer the XAML, so I can deserialize it again multiple times.

    #2 or #3 are each trivially easy to do on their own; but since I can only read the stream once, and there's no way to pass a buffer from my base invocation into the body of my constructor, I can't do both.

    It's not the end of the world; I just changed my constructor to take  a buffer, and I can always add a static factory method that takes a stream. But it makes the API a little more complex, and the factory method can't be used by derived classes.

  • "the base constructor should never depend on the derived constructor having set up the derived state."

    As you explained in http://blogs.msdn.com/ericlippert/archive/2008/02/18/why-do-initializers-run-in-the-opposite-order-as-constructors-part-two.aspx

    this is not true because the base constructor can call virtual methods, whose overrides depends on fields initialized by the derived constructor.

    "In that scenario you can easily accomplish this by extracting the work done by the different constructors into methods, and then calling the methods in the constructors in whatever order you like."

    That doesn't work if the constructor was initializing readonly fields. This solution cripples support for documenting and enforcing immutability.

    "We'd have to add new language syntax to do it."

    Or you could just use the existing syntax for calling a method, allowing that method to be another constructor.

  • Initializing read-only fields has always been the biggest problem with having initialization methods especially since C# doesn't support parallel assignment and multiple return values. Maybe a InitMethodAttribute attribute that relaxes the readonly restriction but can only be called in a constructor?

  • As Robert said, extracting initialization logic into a commonly called method requires you to remove all of the readonly modifiers from your member variables. So its not really accurate to say that "no new interesting representational power is added to the language." On the other hand, I think a better solution to that problem would be to allow an "initonly" modifier on methods. Such methods can write to readonly variables as if they were in a constructor, but can only be called from constructors or other initonly methods.

  • I was just trying to avoid introducing new keywords into the language. An attribute would effect verification not parsing.

  • I like to think of it this way:

    Every constructor calls a base constructor - be it on the base class or on the same class. Eventually, for every constructor you choose, there is a constant array of constructors that will actually be called, starting with object.ctor(). The constructor for object is what actually creates the type and allocates memory, etc. (I know it probably isn't really, but it's a nice way to think of it). So in order to call another base constructor after a base constructor has finished is an error - there'd have to be two types for that to happen. And running code before calling the base constructor would be a worse case - the object is uninitialized. In my view of this model, this would mean there's no 'this', and there's no allocation for fields yet. In any model, this would mean I can call methods on the base class which would still be in an uninitialized case.

    I don't think calling other constructors makes sense, except before your own constructor code. But I'm fully aware of the problem. Consider this:

    class Base {

    public Base(int a, int b) { ... }

    }

    class Derived {

    // both a and b in this case should get the string parameter's hash code

    public Derived(string s) : base(s.GetHashCode(), s.GetHashCode() { ... }

    }

    Remember that GetHashCode is not cached, and could be quite a lengthy operation for long strings. Now it has to happen twice, just because I wanted to call my base constructor with the same argument twice. What if I had a long calculation that returns a Point but my base constructor only accepts an x and a y?

  • Could it be also that you are required to call this(...) at the beginning just in case the chain of local constructors invoked end with one constructor that calls base(...)?

  • I don't understand why new syntax would have to be created. They already created special syntax in the form of base() and this(), so why not just allow that in the body of a ctor?

  • I really dont understand why new sintax would be needed. Why not allow the same sintax we use now but anywhere in the constructor body? base(...) or this(...)

    The biggest pain of not being able to do this is how to set up certain readonly variables. Sometimes you just have to give up on them because of this limitation. There are more cases where this design decision gets in the way but you can usually get around it with API modifications.

    A InitOnly attribute sounds pretty good but the learning curve is IMO steeper than just reusing existing syntax.  How many of us when learning C# have actually tried this(...) or base(...) somewhere inside the constructor body and frowned when it didnt work (I did at least :p). I actually think the learning curve would be pretty small in this case. Of course, the implementation process I have no idea and it probably is pretty expensive.

  • I really dont understand why new sintax would be needed. Why not allow the same sintax we use now but anywhere in the constructor body? base(...) or this(...)

    The biggest pain of not being able to do this is how to set up certain readonly variables. Sometimes you just have to give up on them because of this limitation. There are more cases where this design decision gets in the way but you can usually get around it with API modifications.

    A InitOnly attribute sounds pretty good but the learning curve is IMO steeper than just reusing existing syntax.  How many of us when learning C# have actually tried this(...) or base(...) somewhere inside the constructor body and frowned when it didnt work (I did at least :p). I actually think the learning curve would be pretty small in this case. Of course, the implementation process I have no idea and it probably is pretty expensive.

  • It seems perfectly reasonable to me, from correctness perspective, to allow base/delegating constructor calls in the middle of a constructor, so long as any preceding code does not reference "this" or "base" in any way, either explicitly or implicitly. This can even be made to use the existing language for local variable initialization, and the associated reachability analysis, by saying that "this" is treated as uninitialized variable, and base/delegating constructor call initializes it.

    That said, Eric doesn't seem to be making an argument that it is impossible, or even unreasonable; merely that it is not cost-effective investment of the team's resources. Which is interesting; on one hand, I'd very much rather prefer to see "readonly class" (or something similar) in C# 5.0. On the other hand, as others have rightly noted above, readonly fields are precisely the case which is unnecessarily complicated with the existing, callable-only-at-method-entry constructor invocation syntax, so it could be treated as part of the same problem.

  • > I don't understand why new syntax would have to be created. They already created special syntax in the form of base() and this(), so why not just allow that in the body of a ctor?

    Just because it looks familiar doesn't mean it's not a new syntax. Currently, this(...) and base(...) are not expressions where they appear, for example, but they'd have to become that if they are to put in the body of the constructor. Then you have to come up with various new rules, such as what happens if someone tries to use "this" before calling base(...) - or, if you want to statically check against this, what are the rules for said static checking. Similarly, what happens if the code calls base(...) twice  - or what are the rules for static analysis guaranteeing that this won't happen.

    It may look like "the exact same thing" from the first glance, but I can see how it could easily blow up into a rather large language spec change, with all that entails (don't forget that aside from compiler implementation, there's also IDE support - intellisense etc; testing of it all; writing documentation; and translating all that to all supported languages).

  • configurator,

    I think it would make more sense to have a private constructor that takes an int and have it called by the constructor which takes a string:

    private Derived(int a) : base(a,a){ ... }

    public Derived(string s) : this(s.GetHashCode()){ ... }

    For the second situation I am imagining you mean something like this:

    Derived(Thingie t) : base(t.GetPoint().X, t.GetPoint().Y){ ... }

    The same solution applies:

    private Derived(Point p) : base(p.X, p.Y){ ... }

    public Derived(Thingie t) : this(t.GetPoint()){ ... }

    Honestly I am having a difficult time imagining a situation where a series of constructors like this don't solve most of the problems mentioned in the comments. Perhaps more tortured examples can be found, but I would begin to suspect the validity of the inheritance relationship in those cases.

  • How do we validate arguments before calling the base class constructor? That has always bothered me in both C# and VB.

  • Jonathan,

    Create a validator function, and pass its return value (True if it validated successfully, False otherwise) to the constructor, along with the parameters. Obviously, you have to pass each parameter twice, but it could be worse.

Page 1 of 2 (28 items) 12