Class is out; Static, Sealed, Void

I’m a scripting language kind of guy who like C#, for all its faults. But more and more, I find I can’t forgive the unnecessary sacrifice of class method for static methods. (For the rest of this post, “class/static methods” is used to refer to the grouping of class/static methods, properties, indexers, and events — anything you can make virtual and override in subclasses.)

Eric Lippert (who is on the C# design team) helpfully sorts out that while most people, for good reason, think static means “specific to a type”, it is really intended to mean determined at compile time. This helps explain big shortcomings in the way a sane person might approach class design using C#’s type system.

Using an example idea stolen from the comments of the link previously mentioned, one could easily imagine a class hierarchy of animals. The abstract base class might be Animal, and there might be classes for Lions, Giraffes, Seahorses, Dogs, Lobsters and Tigers, with an abstract Feline class thrown in for good measure. There’s simply no way to specify a property of each species that will be, barring horrific mutation or dismemberment, true for every single instance, and from which you might benefit knowing before any object construction. You can specify either an instance method, in which case you need to create “dummy” animals simply to inspect the default properties, or a static method, in which case you might be able to specify it on the abstract Animal class, but you sure as hell won’t be able to override the method in derived classes.

Interfaces, some of you might say. But if we ignore for a second I object to these interfaces describing traits (IHasAFur) instead of things the class could do (IEnumerable), interfaces won’t solve the problem since due to the definition of static, you can only define instance methods in them, and now we’re back to square one.

Attributes could be another solution. For those just joining us, attributes are pieces of code-as-metadata, similar to Java annotations that can be applied to almost any element of the code, including method parameters, methods, classes, events, delegates and enums.

The crux is that while attributes really are (mostly) special classes and thus code, they are still metadata and therefore constricted to a) contain literal data and b) taking in their assignment and providing for inspection core CLR data types, which expands to the various integers, float, double, string, bool, char and references to other types; not even decimal, DateTime or TimeSpan are welcome to the party. What this means is that at best, what you could do is make a class attribute which could carry the string of the implementing static string, but all this would do is grease the wheels of the custom, gritty, nasty manual reflection code you’d have to write to make this work.

So what it comes down to is that there’s a very simple problem that I’ve tried to solve dozens of times using the type system that I just can’t make work. This is a well-defined issue, and it’s curious in that it’s the sort of thing that dynamic languages solve but not entirely on account of being dynamic. Make class methods work as an addition to the type system and this would be fixed in an instant with type safety intact, i.e without having to “resort” to dynamism (!) or backwards incompatibility (!!), but by bringing the same established concepts of virtual dispatch and overridden methods to the realm of methods accessible by class.

There would be deviations: class methods would be virtual by default — if you want sealed, you have static methods — and also override by default by virtue of being just virtual by default (if the underlying method changes into a static, or for that matter instance, method, it’s an error anyway). And on that note, of course there’d be layering and namespace issues with possible name overlap between static and class methods, but there are issues like that today with collisions between instance and static methods already.

Or, if the design team are still wanting to use the let’s-not-ever-break-CLR-2.0 path, they could just automatically generate a lazily-initialized instance of a hidden, compiler-generated nested class holding the requisite methods, and transform the class methods accordingly.

The good news is that the C# design team seems aware of the gaping hole. Let’s hope they’ll share my philosophy on how to fix it.

Yes, the title of this post is made up entirely of C# keywords. Thanks for noticing.

No comments yet.

Leave a comment

Your e-mail address is never shown. If you type a line break in the comment, it will show up as a line break (naturally). The following HTML is allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

(required)

(required)


Please note: Your comment will not show up at once. Unless you're spamming or being abusive, you have nothing to worry about. (Read the full policy.)