Fabulous Adventures In Coding

Eric Lippert's Blog

Straight from the source

One of the truly great things about working here is that Distinguished Engineers take time out of their busy schedules to answer random questions. Many thanks to Anders and Scott for sharing their insights.

Incidentally, as I've mentioned before, I'll sometimes ask interview candidates how good a C++ programmer they are on a scale from one to ten.  If they say "nine", I'll ask them the kind of question that I asked Scott and see what they say.

(And yes, I was for many years known as "that guy who's always wearing the Tilley hat".  I still have many Tilleys at home, but I usually only wear them when I'm sailing now.)

Published Friday, January 14, 2005 12:18 PM by Eric Lippert
Filed under:

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

 

Igor Tandetnik said:

Note that your question itself makes an incorrect statement:

"... initializing derived class members using constructor arguments before base class constructors run (which seems good, and is what C++ does)."

C++ does not do it this way. In C++, base class constructors run first, then non-static data members are initialized, and finally the constructor body runs. See C++ standard 12.6.2/5
January 14, 2005 1:01 PM
 

Eric Lippert said:

Correct. I was unclear on what I meant there. What I intended to get across was that C++ provides the syntax

class foo : public bar {
int x;
foo(int y) : x(y)

to initialize the member in the derived class. But, as you correctly note, the base class constructor is going to run before the initializer.

What I should have said is "C++ solves this problem by restricting virtual function calls to the most-constructed-so-far type. If we want to have C# objects always act as though they are their most derived type, we could solve this problem by using the C++ syntax for initializing derived class members before the base class constructor is called."

See, it strikes me as odd that you can initialize a derived class member like this:

class foo {
int x = 123;
foo() : base() {

and the initialization happens before the base constructor, but there's no way to do this:

foo(int y) : x = y , base() {

Sorry for the unclarity.
January 14, 2005 1:23 PM
 

Mads Houmann said:

January 14, 2005 2:45 PM
 

Jeff Atwood said:

January 15, 2005 12:30 AM
 

Eric Lippert said:

That's the one. My Tilley of choice is the T3G -- the one with the green underbrim and aussie-style snap-up sides.
January 15, 2005 8:44 AM
 

Tim Carstens [carstens AT seattleu DOT edu] said:

IIRC, in C++ the scope resolution operator (::) can be used to specifiy precisely which class' implementation of a virtual method one wishes to invoke. This is real handy:
class Base
{
virtual void Foo();
void Bar() { Base::Foo(); }
};

If Bar() assumes the implementation of Foo() by Base, it can force that implementation to be used. It's easy to imagine scenarios where a design like this can be confusing, however it's also easy to imagine scenarios like this where it is legitimate.

Besides, good documentation practice would dictate that if Bar() assumed a particular implementation of Foo(), it would say so in the form of a method invariant. In this case, derived objects might be clever enough to maintain the invariant like so:
class Derived : public Base
{
virtual void Foo() { Base::Foo(); ...}
};
If this convention were adopted, Base::Bar() would not need to use the scope resolution operator. Clearly this design is restricted to scenarios where Derived::Foo() and Base::Foo() will not interact inappropriately.

Frankly, I don't know if C# provides similar functionality. If it doesn't, I can't help but wonder why, since it is not a feature that can be used "on accident," and it allows the developer to maintain access to code that has already been written (and thus preserves the principle of code reuse). Lastly, it allows developers to specify precisely which implementation they require, which allows invariants to be maintained.

It is also interesting to consider the question from the perspective of state transitions. Assuming no side-effecting methods, an object method either queries the state of the object, or it is intended to move the object into a new state. By convention, method naming indicates which state the object is supposed to transition into. Polymorphism complicates this model when base classes use polymorphic helper methods to alter their own state. This presents some interesting problems in terms of dependability, but this post is long enough without analyzing the implications of dynamic binding.
February 3, 2005 8:43 PM

Leave a Comment

(required) 
(optional)
(required) 
Submit

About Eric Lippert

Eric Lippert is a senior developer on the Microsoft C# compiler team. Before that he worked on the framework of Visual Studio Tools For Office. Before that, he worked on the compilers, runtimes and tools for VBScript, JScript, Windows Script Host and other Microsoft Scripting technologies. He lives in Seattle and spends his free time editing books about programming languages, playing the piano, and trying to keep his tiny sailboat upright in Puget Sound.

This Blog

Syndication


© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker