Any Way the Wind Blows
With the rate of turnover for developers of Ventozoom's flagship application, some part of the system must be cursed. After Robert joined the team, and seeing how his predecessor handled dictionaries, he can understand.
Since landing at Ventozoom six months back, Robert has been working on a single application -- a rather complex .NET application with a cryptic code base to match. Rumored to be responsible for several employee separations, it's the kind of application that started life as an innocent, quick-and-dirty hack solution for a small group of customers who, with the help of a team of aggressive sales guys, rapidly grew.
And with the number of customers, so grew the requests for new features.
Add to the resulting mix of shifting requirements and feature creep, the usual ingredients that you need to transform a problem into a really big mess crept forth: lack of manpower, lack of competence in the available manpower and, last but not least, lack of time. In other words, over the first few years the product was developed by just a handful of people out of their respective technical depths, with too much work to do and not enough time to do it, or enough sleep for that matter.
But the application makes the company piles of money, so it's OK … right?
Hooray for Hash Codes!
While basic hashing implementation and equality comparison in the Object class does allow containers like the .NET HashSet<> to work with any type without any special preparations to the value class, it's also the source of a myriad of (sometimes subtle) software bugs: If GetHashCode is overridden, a consistent implementation of Equals usually also has to be provided (and vice versa), and if equality depends on the object's state (that is, more often than not) the object has to be immutable (because the hash code has to be).
Of course, not every programmer knows about the subtleties of the special twins GetHashCode and Equals. And why should they? One does not have to burden one's self with all this complexity to simply enjoy the fact that any type can be put inside a HashSet, or used as a key type in a Dictionary -- for that matter -- just like Robert's predecessor apparently did.
When refactoring some old code (or, rather, gently lobotomizing it with a virtual chainsaw), he found this:
Dictionary<Dictionary<string, string>, Dictionary<string, string>> projectAttributes = new Dictionary<Dictionary<string, string>, Dictionary<string, string>>();
Dictionary<string, string> newAttributes = ProjectUpdate.GetMappingAttributes(projectObject);
Dictionary<string, string> savedAttributes = ProjectUpdate.SaveMappingAttributes(projectObject);
Robert was intrigued. A Dictionary (the .NET version of an associative array) of Dictionary to Dictionary? Or perhaps ... a Meta Dictionary. He had, of course, already seen quite some "interesting" code during his career, but this one was new and he couldn't figure out what the purpose of that construct could possibly be. That is, until Robert found the place where it was used.
Key-Value Pairs FTW!
Turned out, Robert's predecessor had been looking for a tuple data type, and in the good ol' days of the Microsoft .NET Framework 3.5, there was none -- at least not built-in. So, naturally, the opportunity to do your own thing, however that may be, was wide open:
Dictionary<Dictionary<string, string>, Dictionary<string, string>> projectAttributes =
Arguments.Attributes as Dictionary<Dictionary<string, string>, Dictionary<string, string>>;
foreach (KeyValuePair<Dictionary<string, string>, Dictionary<string, string>>
projAttributes in projectAttributes)
newProjAttributes = projAttributes.Key as Dictionary<string, string>;
savedProjAttributes = projAttributes.Value as Dictionary<string, string>;
Robert thought the logic through for a minute -- what is a 2-tuple other than a key-value pair? And what is an associative array other than a list of key-value pairs? And what is a single value other than a list with one entry? (And what is a foreach loop over that one entry other than calling First?)
Looking at it from this angle, it almost becomes the most natural thing to use a Dictionary with precisely one entry as a 2-tuple. Almost.
Again, all this joy is only possible because every .NET type implements GetHashCode. Sometimes, Robert still wonders if the creators of the .NET Framework really thought about what things they would help to let loose on the world of source code.
About the Author
Mark Bowytz is a contributor to the popular Web site The Daily WTF. He has more than a decade of IT experience and is currently a systems analyst for PPG Industries.