One of the things that constantly surprises me is the differences in value placed upon knowledge by those that have it and those that lack it. It often seems that anything that one knows is considered trivial or easy - and that anything one doesn't know is correspondingly complicated or hard.
Thus it is not uncommon to see a developer who spent days or weeks learning how to manage a technology expecting another to "pick it up" in a matter of minutes. Naturally, as developers are not a race apart, this also happens in other areas of endeavour: I've seen chess players run through the moves and rules in less than a minute and expect the explanation to be understood. Or those versed in cooking giving explanations of a recipe that would only make sense to someone that already knew most of the answer.
On the other end of such discussions the slightest confusion or ambiguity becomes a major setback and an obstacle to understanding. However, to my bemusement, the enigmatic mutterings are not seen as a failure of explanation but as a failure of understanding.
This is the context in which Overload operates: we all have pieces of knowledge that may be of use to others - but we fail to see the value in them and often lack the expertise to explain them. There can be very few of you reading Overload that do not have some knowledge or expertise to share, and the "readers" are here to provide assistance in conveying such expertise in a manner that is comprehensible. One only has to note the number of authors that feel the need to acknowledge their assistance to realise that this assistance is both necessary and valued. But most importantly it is available.
Why am I telling you all this? It is because Overload is dependent upon the willingness of ACCU members to write for it. And, despite the increasing number of ACCU members the number writing for Overload is not healthy. We get by but, on this occasion, it was only achieved by the last minute efforts of a number of contributors who responded to a plea from the editor. To avoid placing that pressure on them again, I'm making a plea now: please make a contribution to Overload. This means you!
Think back over the last week: how many things have you explained to other developers? How many of these do you understand well enough to think, "no-one would be interested in that"? Well, those are the things that you are expert enough on to write about. Try it - most of the authors find that the feedback they get makes the effort worthwhile.
And speaking of feedback: I'd like to thank all of those that helped with this issue, especially those that contributed to the last minute effort to fill the pages. I know that this time of year there are other demands on your time.
There is rhetorical value in the number three ("The Three Bears", "The Three Billy Goats Gruff", or any number of political speeches). And it is also said that accidents happen in threes. I'm sure that the following three incidents don't quite qualify as accidents - there was a certain amount of intent involved. But they certainly represent missteps, did come as a triplet, and reflect some of the difficulties that occur when working in our field.
There is often a need to store arbitrary elements of configuration information and developers in many programming languages have come up with the same approach: store an associative collection of strings mapping keys to values. The keys provide convenient tags for values to be retrieved without the collection needing to be written with any knowledge of the information stored. And, since most languages allow values of various types to be represented as string values this affords the necessary degree of flexibility. Sometimes other types of value are used as a key (see "The tale of a struggling template programmer" [Overload 61] or its sequels [Overload 61, 62]), sometimes it is possible to store the values without converting their type.
In Java I've use the Properties class for this purpose and wrote a translation of this design in C++ for a recent project. The translation wasn't exact - there are a number of design decisions in the Java libraries that I find questionable. For example, the Java library treats Properties as a specialisation of HashMap whereas my implementation used delegation to a std::map . In a strongly typed language why allow a Properties class (which specifically contains String s for both keys and values) to be treated as a HashMap (that can contain arbitrary objects). Anyway, I did things my way and refused to expose the container interface.
The implementation language forced another difference - C++ doesn't allow null references, so I had to decide what to do when an invalid key was supplied. My decision caused a lot of discussion during the code review (yes, this client has code reviews; no, the moderators don't stop digression into solutions). What did I decide to do? Well, as I intend to cover the design options later, I'll avoid that discussion at this point.
The code went into production and I didn't look at it for several months. I had no reason to until I happened to revisit some code that had used it - when I noticed that the classname had changed. Curiosity aroused I went to have a look. During the project lifecycle the original properties class had been renamed to foo_properties and "improved" by giving it a constructor that parsed a domain specific string format and a member function to produce such a string. This format (similar to field value pairs in a URL) contains embedded key/value pairs. The developer in question needed this functionality and was evidently convinced that this was the right class to support this functionality. (After all there was no other class to which these functions belonged!) There is even prior art: the Java library Properties class can serialise and deserialise itself.
Personally I didn't (and don't) see why these functions belonged as part of this class. It already did one thing well, and adding a second role makes it less, not more usable. The class didn't need these functions to perform its role: they could be implemented efficiently via its public interface. And, if cohesion isn't a strong enough argument then consider the coupling introduced: the properties class was now attached to this foo string format.
There are several points to be considered here: when the change was made there was only one client of the properties class, so it was simple to make the change. It is also a good pocket example of how adding functionality to a component reduces its reusability. For many of our colleagues this is counter-intuitive and a good supply of examples is needed to convince them otherwise.
By the time I saw it, the code was in production (changes manage to achieve that without being reviewed) and there was enough work to do without fixing things that were not manifesting problems to the user. (Like fixing things that didn't work.)
"How do I return a NULL string?" came the voice from behind me. Like most of these questions it is worth finding out a bit of the context: I could guess that the language was C++, but why would anyone want to return a NULL std::string ?
The answer to that wasn't illuminating: "because that's what I'd do in C". My colleague knew that in C a string is represented as a char* and that can be NULL. But he also knew that a C++ std::string cannot be NULL. Stop. Rewind. What was he trying to do?
It turns out that the problem is how to indicate a lookup failure in an associative map of string key to string value. And, as with the way my colleague would have implemented it in C, returning NULL is exactly the choice made in the Java library's Properties class:
public String getProperty(String key)
Searches for the property with the specified key in this property list. If the key is not found in this property list, the default property list, and its defaults, recursively, are then checked. The method returns null if the property is not found.
So there are precedents for returning NULL. Also, in the C++ standard library is a similar solution in a different but analogous situation. From "Associative container requirements" (23.1.2/7):
returns an iterator pointing to an element with the key equivalent to k , or a.end() if such an element is not found.
This may not be NULL, but it is definitely a special value - with all the difficulties that this causes the client code.
Returning to Java the Properties class also provides an alternative solution:
public String getProperty(String key, String defaultValue)
Searches for the property with the specified key in this property list. If the key is not found in this property list, the default property list, and its defaults, recursively, are then checked. The method returns the default value argument if the property is not found.
While we are considering possible solutions there is another one in the C++ standard library. (From 23.1.1/12)
The member function at() provides bounds-checked access to container elements. at() throws out_of_range if n >= a.size() .
Lets recap: we have seen three possible behaviours in the face of a request for the value associated with an unknown key:
Return a special value to indicate failure
Return a default value supplied by the caller
Throwing an exception
While these may all be reasonable solutions they are not all appropriate to every situation. And, there are additional options: "fallible" return types; stipulating the result as "undefined behaviour"; aborting the program; user-supplied callbacks and status flags (of various scopes) indicators are all possibilities (but less commonly used).
In order to recommend a solution it is necessary to know even more about the problem. It turns out that my questioner was in the process of designing a class to hold the configuration parameters for an application. Hey! That sounds familiar, maybe there is some prior art - even an existing implementation somewhere?
But before I could look for prior art or a library to use my questioner was gone with: "the configuration values should be there - I'll throw an exception. Thanks!"
When I started this editorial I had three discussions of implementations of "Property" classes to discuss. But between then and now one of them has evaporated into the mists of memory and been dispersed by the force of ongoing commitments. I'll have to trust that you have your own story to tell.
I fear that you will.
I wonder: how many times has this particular wheel been invented?