I’m really impressed with how deep an interview can go over the seemingly innocuous example of shapes inheriting from one another.
First, it’s easy to start it off in a way that weeds out incompetent people without wasting competent people’s time. We can start with, “I’m going to name four classes, and I’d like you to describe the relationships or interactions you would assume they have, just based on the name, okay?” The classes we name off, in alphabetic order for lack of a better one, are: Canvas
, Circle
, Rectangle
, and Shape
.
Hopefully candidates come up with the idea that Circle
and Rectangle
inherit a method from Shape
that takes a Canvas
argument, because that’s how classes named like that normally behave. There’s a bit of room for reasonable deviance here; candidates who have never done any GUI work may reasonably assume that Canvas
is a specialized kind of Rectangle
and therefore inherit from it. We should be prepared to suggest clarifications and see how long it takes them to be coaxed into understanding the relationship. I wouldn’t be surprised if this somehow turns out to be a really good metric of hire-ability, some constant divided by the time it takes them to understand the relationship among these four classes. Of course, some teams may be satisfied with just this, but let’s assume that we want top talent.
What’s great is that this question can go in a number of directions when we actually get to code (I’m assuming Java).
- If we want to test their algorithm chops, we can tell them that Canvas has a method to draw a point at a coordinate and have them implement the
Circle.draw(Canvas)
method.
- If we want to touch on concurrency, we can tell them that every shape has a
ReadWriteLock
and that the fields should be accessed and modified appropriately.
- If we want to put a little pressure on their class design muscles (or just weed out any Java programmers who haven’t learned anything new for a decade), we can tell them to use a class parameter as the type of their coordinates, like
<C extends Number>
.
The way to really see if we’re dealing with thinkers, though, is to throw Square
in the mix at some point. The natural idea is that, since all squares are rectangles but not all rectangles are squares, that Square
should inherit from Rectangle
, and perhaps this is exactly what we want from immutable objects. However, a mutable square poses a problem, namely that it cannot be modified like any old rectangle and still be guaranteed to stay a square. If a square inherits methods from rectangle to set its length and width separately, it’s probably busted. Now we have to, what, meticulously override these mutators to call multiple mutators from the super-class? I don’t like it; it’s not elegant. Sure, Square
doesn’t have to inherit from Rectangle
, but wouldn’t it be nice to have that polymorphism for read-only algorithms? (Not sure if anyone who mentions contravariance right around now gets bonus points or undying scorn.)
The conversation (no longer really an interview if it’s still going strong at this point) now brings us to questions of how to balance composition and inheritance, how to communicate to programmers about mutability through API design, and the obligatory esoteric contentions like how to use the term polymorphism correctly.
Well, if we only have time for one interview question, this may be a decent choice because it is versatile and gets progressively more selective.