March 21, 2007
Names are important
For a profession that is all about naming things, most programmers are being terribly careless with names. Although you get away with it most of the time, you look so immensely stupid when two pieces of code disagree over the meaning of a name. Names are important.
One of the things I still love about Perl is that, by convention, it is considered rude to invade other people's namespace. So we put all our public methods and constants into the @EXPORT_OK array and let the client decide which part of that he wants to use in their code. I should be able to do the same with code extending existing classes: Let me decide which extensions I want patched in on a per-class basis. I believe extension methods in C# 3.0 work this way. Do copy this.
Another name issue few languages get right are namespaces. Namespaces are important, because sooner or later you will have two different Node classes in your project and you need to tell your code which one to use. Let's look how some popular languages are dealing with this:
- PHP
-
Bashing PHP is a bit like beating up an old man, but here we go anyway: PHP has no notion of namespaces at all. To work around this, people are using
Really_Long_Classnames_With_Packagish_Names_Prefixedto lessen the chance of namespace clashes. LOL. - Java
-
Has a wonderful culture of putting classes in packages named after some domain you own. So my
Nodeclass would be packaged asorg.netalive.swsu.Nodeand people couldimportthis name and just writeNode. Bad: When you need to use two differentNodeclasses in the same piece of code. As you can only import oneNodewithout name clashes your code will look likeMap<Node, incredibly.long.package.name.of.other.Node>. Horrible when it happens, and it happens frequently. For instance, both the most basic GUI widget in Swing and the most basic data structure in Java are calledList. - Perl and Ruby
-
Uses
Package::Subpackage::Classnamesyntax for improved looks, but since you cannot import or alias these long names, this is more about organizing files and not really better than PHP'sPackage_Subpackage_Classnameworkaround. At least you can switch into a namespace and add and replace methods without using fully qualified names. It's kind of OK for untyped languages because you only need to reference types when calling a constructor or another static method. Still the possibility of anotherTree::Nodeclass in a second library is always there and sometimes urges you to use more unique package names than you would like. - Python
-
I don't speak Python, but from what I've seen this is a language that got namespaces right. You can import a namespace as in Java, you can selectively import symbols as in Perl, and here's the goodness: You can
import reallylongmodulename as shortcutto aliasreallylongmodulenameintoshortcut. Nice.
I think what Python does (importing and importing into aliases) should be the minimum requirement for any language that wants to take names seriously. The package naming convention from Java is cool, because the DNS is the only naming scheme humanity ever reached something like an agreement over, and unique names are good. Imagine blowing up the planet because some piece of code felt ambivalent about the semantics of System.Nuke. We would look all kinds of stupid if this sort of thing ever happened.
March 20, 2007
Whoops! Open classes not cool after all!
Ruby, Perl and many other languages let you reopen an existing class or namespace and add additional methods to it, or replace existing methods with new code. Everyone thinks that is "like super-cool" and "really feels the spirit of getting things done", probably accompanied by some generic "LOL Java, agile languages FTW!" rant.
Surprisingly, open classes have one serious problem: People are using them!
Right now the two most popular uses for reopening classes are (1) adding methods to core classes like objects or lists and (2) patching totally not public code with your own funky version. Both are terrifyingly bad ideas which will probably break with the next update of the code you're patching, or as soon as another clever library attempts to do the same. But let's enjoy some examples together:
It is impossible to use prototype.js and json.js at the same time because prototype.js does something nasty to Object.prototype. But never mind since these are only the two most commonly Javascript libraries on the planet.
What Rails is doing to the Ruby core, and what some plugins are doing to Rails, is downright scary in some places. Thankfully Rails is heavily maintained and bugs are patched quickly.
While developing a World of Warcraft addon in Lua, we discovered that the preferred way to intercept chat messages was to replace the existing message handler, intercept the messages you need and hand over the rest to a copy of the old handler. Unfortunately, since our addon name was lexically smaller than the name of another addon that used the same trick, and World of Warcraft loads addons in alphabetical order, our new message handler was replaced by a third addon handler by that other, lesser addon and everything went to hell.
I'm not even sure if the last example is valid in this context, but it's also about bad scope and globals, and I really needed to stress the fact that I'm writing kick-ass World of Warcraft addons this very minute.
Anyway, don't you think it's funny how twenty years after people realized that "globals are teh suck" we're falling into the same bad habits all over again? Yes, open classes are fun toys to play with, but you can also fuck up royally if you don't pay attention. So, please, do think about what happens when other libraries attempt to pull the same hackery as you. Do consider the chance that a second library also wants to decorate the draw method, and do assume it will also save the existing method using alias :original_draw :draw. And OH MY GOD do not patch up private methods that have clearly not been cleared for public consumption by the original author!
Patching private methods. I mean, what the hell. Think of the children!