Six out of ten ain’t bad

Occasionally I interview C++ developers. I’m always interested in how people rate themselves, so I’ll occasionally ask a candidate, “On a scale from one to ten, how do you rate your C++ skills?”

The point of the question is actually not so much to see how good a programmer the candidate is — I’m going to ask a bunch of coding questions to determine that. Rather, it’s sort of a trick question. What I’m actually looking for — what I’m looking for in almost every question I ask — is “how does the candidate handle a situation where there is insufficient information available to successfully solve a problem?” Because lemme tell ya, that’s what every single day is like here on the Visual Studio team: hard technical problems, insufficient data, deal with it!

The question has insufficient data to answer it because we have not established what “ten” is and what “one” is, or for that matter, whether the scale is linear or logarithmic. Does “ten” mean “in the 90th percentile” or “five standard deviations from the mean” or what? Is a “one” someone who knows NOTHING about C++? Who’s a ten?

Good candidates will clarify the question before they attempt to answer it. Bad candidates will say “oh, I’m a nine, for sure!” without saying whether they are comparing themselves against their “CS360: Algorithmic Design” classmates or Stanley Lippman.

I mention this for two reasons — first of all, my favourite question to ask the “I’m a nine out of ten” people actually came up in a real-life conversation today: OK, smartypants: what happens when a virtual base class destructor calls a virtual method overridden in the derived class? And how would you implement those semantics if you were designing the compiler? (Funny how that almost never comes up in conversation, and yet, as today proved, it actually is useful knowledge in real-world situations.)

The second reason is that ten-out-of-ten C++ guru Stanley Lippmann has started blogging. Getting C++ to work in the CLR environment was a major piece of design work, of a difficulty that makes porting JScript to JScript.NET look like a walk in the park on a summer day.

Compared to Stanley Lippmann, I give myself a six.

Comments (16)

  1. Philip Rieck says:

    After the "I’m a nine", I always ask them "what question would you ask someone who was an 8.9 that they would have difficulty answering – just general subject is fine, but a specific question is great". The real nines have a question like (I normally tech .net) "what should you look out for when casting a structure to an interface and calling methods that modify the data". The non-nines say "Something about how inheritance works". If nothing else, it really gives you an idea of what they find hard about what you’re teching them in.

    The great part about this is, I can then use the good questions on people later! And, if they have good questions I can learn something, too (after watching PDC speakers and going to ask the experts, I had to re-rate myself. I used to say I liked feeling stupid, but ouch — ego blow. And if you’re a six, I’m not saying what I am) .

  2. Dan Shappir says:

    With regard the 1-to-10 scale and insufficient data: I think that in this case cultural norms fill in most of the blanks. For example, it’s quit clear the scale isn’t linear, most human scales aren’t. The differences between 2 to 3 to 4 are generally insignificant while the differences between 8 to 9 to 10 are huge.

    I think the answer to the question provides more information with regards to that person’s ability to accurately judge his or her own capabilities, the personal honesty to accept this judgment, and the guts to give you the correct answer. Without additional questions, it’s you who doesn’t have sufficient data to evaluate the answer.

    I personally have never used this question, but I’ll certainly consider it. A good question I’ve recently learned about is: "which good CS book have you recently read?" Obviously this question is better suited for someone who is not straight out of the University.

    A question I might ask somebody answering 9 is: "why is it a bad idea to overload the && operator?"

  3. Eric Lippert says:

    Indeed, ability to rate one’s knowledge of a subject accurately is strongly correlated with one’s knowledge! Dilletants tend to compare themselves against their peers, and hence produce inaccurate ratings; experts tend to compare themselves against gurus.

    As for the && operator — I don’t think I’ve ever actually overloaded an operator other than "new". It’s not very often that one needs to add two parsers together. I’ve always disliked the entire idea of operator overloading — making << mean "stream to a file" struck me as incredibly disgusting when I first heard of it, and my opinion hasn’t improved since then.

    I can think of lots of reasons to avoid overloading in general. Something that strikes me about the && operator is that it is a short-circuiting operator — one might imagine that this would lead to bizareness when overloaded.

  4. Dan Shappir says:


    Exactly. Say a and b are expressions of type bool. If you write:

    c = a && b;

    if a is false b isn’t evaluated at all – short circuit.

    If a and b are expressions of UDT X with an overloaded && operator then the previous expression translates to a function call:

    c = X::operator&&(a, b)

    In this case both expressions are evaluated regardless of their values. This discrepancy in behavior is why overloading binary logical operators is a bad idea.

    I agree that in most cases operator overloading can detract rather than enhance readability (BTW you can pass this sentiment on to whomever elected to use += with delegates). OTOH where would a string class be without an overloaded + operator?

    And on a related issue, another 9 question: what is Koenig lookup?

  5. Dan Shappir says:

    For more discussions of "weird" C++ stuff check out the thread:$6697

  6. Eric Lippert says:

    That question is a little too jargony. Case in point: I once wrote an internal spec describing the insanely complex rules that JScript .NET uses to resolve overloads at compile time and run time. I could certainly describe algorithms for argument-dependent name resolution, why you’d want to use them, and what the practical pitfalls are when using the Reflection layer to do so, but until two minutes ago I didn’t know that this was called "Koenig lookup"! (I’m sure that Herman, who actually implemented that algorithm in JScript .NET, knows that it’s called Koenig lookup, but he’s got a PhD in language design…)

  7. Eric Lippert says:

    I actually kind of like += for delegates, though it struck me as odd at first. It gets across the idea that you are adding something and at the same time modifying the LHS. However, when designing a new language, one can add new keywords and operators pretty easily. I personally would have created a new operator or syntax rather than overloading += in this weird way.

    Next time I see Anders I’ll ask him what motivated that decision. Don’t hold your breath waiting — I haven’t had a meeting with Anders in over six months.

  8. Peter Torr says:

    I know Herman was against += as well. JScript’s method of directly calling add_EventName() and remove_EventName() seems kind of klunky, but at least you know exactly what is going on.

  9. Mike says:

    Or hey, AddHandler from VB.NET. :-)

  10. Centaur says:

    [quote]what happens when a virtual base class destructor calls a virtual method overridden in the derived class?[/quote]

    Is a 9-out-of-10 supposed to say, without looking up, something along the lines, “Chapter 12.7 ‘Special member functions – Construction and destruction’, verse 3 of The Holy Standard says, ‘When a virtual function is called directly or indirectly from a constructor or a destructor, and the object to which the call applies is the object under construction or destruction, the function called is the one defined in the constructor or destructor’s own class or in one of its bases, but not a function overriding it in a class derived from the constructor or destructor’s class, or overriding it in one of the other base classes of the most derived object (1.8)’. Thus, the virtual base class V destructor V::~V shall invoke the virtual method V::f, not the overridden D::f”?

  11. Dan Shappir says:

    I personally would not expect the 9-out-of-10 to quote chapter and verse out of the C++ standard (I would probably be somewhat scared if he did). I would expect him to understand the implications. For example, the "indirectly" bit is very important. Misunderstood it can result in application misbehavior that this person would simply not understand, and thus be unable to correct.

  12. Centaur says:

    By the way, my first reaction was, “Is it even legal, to call a virtual method from a base destructor, when the derived object has already been partially destroyed?” Then, after digging into the standard, it turned out it is. Oops. Anyway, this is a questionable practice.

  13. Eric Lippert says:

    It’s a terrible practice. But to answer the question, no, I don’t expect 9/10’s to have memorized the specification. I do expect that 9/10’s should be able to say something like:

    "I don’t know offhand,but let me see if I can reason it out. The base class destructor runs after the derived class destructor. That means that when the virtual function is called, all the state that makes the derived class different from the base class has been destroyed. In a sense, after the destructor runs, the "this" pointer really isn’t pointing to a valid instance of the derived class anymore! Therefore, I’d expect that a virtual function call would call the base class version, because the derived class version might depend upon now-destructed state. This would be pretty easy to implement — the derived class destructor could, as its final act, change the virtual function pointer to point to the base class vtable instead of the derived class vtable."

    That’s a 9/10 answer. It demonstrates that the candidate understands destructors, virtual functions, how virtual functions are implemented, and most important, that the candidate can think like a language designer. Deciding what the "for" loop syntax looks like is easy. The hard part of language design is figuring out the right thing to do in these weird corner cases.

    Sometime I’ll tell you guys about the new data type that I tried to get them to add to VB.NET — a variation of the Variant that I called the "Deviant". Now _that_ was a host of corner case bugs waiting to happen.

  14. Couple interesting links on related topics (Disclaimer: Not Necessarily Directly Applicable to Your Situation!):