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.

PRAM

I’m currently in a phase where I’m trying to get rid of a lot of my old stuff. I don’t usually mention my age around here because I don’t feel it’s relevant, but rest assured I’m a few months shy of 23. A few years back I did entirely different things all day than I do now, and it’s a fact that returns to shock me with some regularity.

Tonight I was cleaning out my stack of old computer magazines and I found a printout of an old and mercifully unpublished web site I made about me. I don’t make web sites about me because that’s a terrifyingly un-me thing to do; readers might even call this post uncharacteristic. But this one reminded me of one of my younger phases when the new millennia had barely cooled.

I mentioned this (and apologized) to my friend StevenRoy, the person I’ve known online for the longest by far, and a man I am happy to still talk to on a regular basis. He observed that “If I remember correctly, you were trying really, really hard to be Douglas Adams.” which is true.

It is also funny since Douglas Adams once wrote: “In fact, I wanted to be John Cleese and it took some time to realize the job was in fact taken.” Let’s just hope that someone won’t continue this lineage by trying to be me, because I can attest that it’s a lot harder than it sounds, immaculately cleaned of rewarding upsides, and I don’t think there’s a lot in it anyway.

The River of Posts

If I can’t click a link at the front page of your weblog to see older posts — not just the next older post, but older posts — and then continue going back and forth along the same lines, you’re doing it wrong. (Also, if this is referred to as “Next”, which implies “forward”, which implies “in time”, which implies “future”, and/or if the corresponding link to go to newer posts is named “Previous”, which implies “past”, you’re definitely doing it wrong.)

Fundamental

There are three languages that I really don’t like.

I really don’t like C++, because it tips the equation of “what’s less likely to increase dramatically over time, and what should we therefore choose to optimize for — CPU or man hours?” on its end. It may be great for Mars landers, operating systems and embedded systems where you really need to know what to allocate on the stack or the heap, and in which order to destruct it, but that’s not what it’s most often used for. That such a convoluted package of statements and pseudo-backwards-compatibility still thrives today is a concept I cannot grasp without the aid of powerful narcotics.

I really don’t like LISP, and here I mean LISP the API culture and not LISP the husk of a fundamental language. LISP may have helped gel a more complete and at the time drastically different view to a programming model that helps enormously today, and I don’t dispute it. (I strongly suppose that its supporters would deride me as “missing the point” no matter what I wrote even if I “acknowledged” its entire “heritage”, “superiority” and “innovation”.) But what bugs me is that here stood a bunch of people intent on starting over without focusing the language design on hardware specifics, without even worrying about memory management, and the best constructs they could think up were these horrible atomic things like cons and car and cdr. LISP smells like a language to build a compiler to, not to get stuff done in; it smells of interpretive dancing with language constructs instead of writing what you mean. (Which doesn’t prevent people from getting stuff done in it; I’m just saying that I’ve never been mystified about how LISP isn’t taking over the world.)

I really don’t like Python, and I wish I could give a specific answer to why. Smart people with glasses and degrees get things done in it and they work fast, but I’ve never been able to juice that out of the language. Python isn’t “executable pseudocode”; out of all the languages I have difficulty writing, Python trails even AppleScript. It may be true that Ruby is my current favorite language, and that Perl was my first favorite language, but I’ve never planned resentment towards Python. Trial after trial, it has earned it by being obtuse and difficult, at least towards me.

I don’t like not liking things like these. I see qualities in most languages or technologies I don’t like, which makes it bitter for me. I feel like I’m missing out. I’m missing out on frameworks like Django from Python, I’m missing out on a LISP culture in which metaprogramming is established and default (although if I had to write code using those primitives, I’d want to effectively generate lots of code too) and I guess I’m missing out on performance, although given what I’d have to give up to get there in C++, it’s clearly not worth it for me.

I can see the arguments for people that would like to slap me in the face for saying these things. I like Ruby, Objective-C, Perl and C#. It’s not hard to shoot them down with “weird community and language”, “strange hybrid”, “it looks like line noise” and “from my parents’ home in Wyoming, I stab at thee. They are often not deep, well-argued points of view, but sometimes they are, and even when they’re not they are real opinions, formed for a reason. Often, people who don’t like LISP and C++ but prefer C# have run to whatever course Microsoft has offered, decided after basic training that this is close to manna and never seriously tried to learn, never mind gain appreciation for, another language. I can only conclude that I’m not that person.

Programming is evolving so quickly now that it’s hard to see if or when a plateau will be reached. LISP guys may tell you that it doesn’t mean anything since they invented everything forty years ago anyway. C++ guys may tell you that it’s all syntactical crap that gets in the way of “performant” execution. Python guys may tell you that for form and structure, it’d be really nice if I had a fitting stereotype to round out this summary.

But like a friend is fond of saying: the more you know, the less you know you know, and the more you know it. Sharpen this a bit and apply it: If these arrogant LISP fuckers think they invented it all and the rest of us have spent the last few decades “badly reimplementing everything”, how much do they really know?

Older posts »