A friend lamented to me last week about the absence of
abstract static members from class definitions in Java:
Turns out you can’t do it in C# either. Common understanding is that the absence of such a feature from these languages is an limitation in the language implementation (Java, C#). I’ve come to the realisation that there might be a very good reason as to why you can’t have
abstract static members in these languages, and I think it’s due to a problem with the way we understand the
I think we might be thinking about the
static keyword wrongly. The
static keyword is used for instance-independent functions and data. Instance-independence, however, doesn’t really make sense in an object-oriented context.I’ll explain this in a second, but fundamental to understanding that is an understanding of the way that programmers view class definitions.
What do class definitions really represent?
The tweet presented at the start of this article perfectly represents the way that many programmers think about class definitions. There are two main components here:
- Class definitions represent a type of object, and
- A class definition defines a set of properties common to all objects of that type.
With such an understanding, it’s easy to see where the need for an
abstract static member comes from. Like in the Porsche example earlier, sometimes, each subclass of a class will share a common property, and this property should be implemented to be common across all instances of the subclass.
The difficulty in this understanding is that it’s very nearly accurate. What I think a lot of programmers get wrong when it comes to OOP is that class definitions do not represent a type of object, but represent a contract of characteristics that each instance is guaranteed to fulfil.
In the same way that classes implement interfaces, instances (objects) implement class definitions. In their purest form, class definitions specify specific data and functions that class instances will hold - no more, no less. They make no guarantee of type or commonality between instances of the same class.
This is wholly consistent with the notion of classes as objects - our superclass
Car simply requires all instances to fulfil the contract of having a
Model, and cares not for the implementation details, including whether there are subsets of
Cars with common
Models. Asking the superclass to understand this by marking its members with
abstract static requires a tighter coupling than should be used in such scenarios.
Implications for the
If a class definition is simply a contract of characteristics, or an interface that instances are expected to fulfil, then the notion that static members represent common properties of the type is wrong.
What are static members actually for, then?
I’d argue that static members are simply a convenience to the programmer, somewhat divergent from true object-oriented design. In my own experience, I’ve only ever used static members when I’ve somehow needed to manage or coordinate multiple instances of a class. Take a look at the following class definition, defining a member contract for an animal on a farm (example in C#):
Animal class is split into two parts - the non-static members define the actual data pertaining to the
Animal contract, and the static members simply manage the integration of the
Animals within their broader context.
You could just as easily express the same functionality like this:
Using this architecture,
Animals are still guaranteed to have unique IDs within their broader context -
Farm objects - without having coordination logic embedded within the
If you’re not expressing your class in this format, you’re probably violating the Single-Responsibility Principle - you’ve simultaneously got a class that is used for
SomethingOrOther-ing and the static aspects of that class, that coordinate
Here’s a challenge for you - try re-writing the
static keyword out of some of your old code. It may take a little getting used to, and it’s certainly not always necessary, but it will be helpful for understanding that
static is a convenience keyword only, and not an integral part of Object-Oriented design.
A final note on
As for our opening example - “all Porsches have the name ‘Porsche’” - I disagree; you’re thinking about classes wrong. “Porsche” is the make of the individual car, and the fact that it is a value common to a subset of
Cars should merely be a coincidence to the
Car superclass. I’ve got no problem with thinking about this specific issue without the use of the
static keyword, with: