
Scott Meyers wrote:
I have a question about library interface design in general with a strong interest in its application to C++, so I hope the moderators will view this at on-topic for a list devoted to the users' view of a set of widely used C++ libraries. In its most naked form, the question is this: how important is it that class constructors ensure that their objects are in a "truly" initialized state?
I find it essential that if something is truly a class, and not just a struct with some member functions, that the constructor leaves the Foo as a Foo and not as an almost-Foo or sort-of-Foo. Arguments for partial construction of a class are almost always from the mentality of C programming, and ignore the concept of invariants - indicating that the one ignoring them has a weak grasp on the usefulness of user-constructed types. Instead of giving you the same answers that have been presented so many times in books, lectures, on the net and even in the Boost mailing lists, let me use a bit of rhetoric to rephrase your question: How important is it that the items you use in everyday life arrive at the point of your using them in a fully constructed state? Say... a vehicle, a computer, a building, a dentist's knowledge... and the list goes on and on. If I'm given a Thing, then let it be a real Thing and not a "carboard imitation". In my experience, if I'm fixing a bug in some code and notice that an object is constructed in multiple phases, then I immediately start redesigning it so that each invariant is a distinct type. When I'm done I've spent about as much time "refactoring" it and testing it as I would have spent fixing the original bug. However, the original bug is gone and I've removed my need to look at the code again in the future for the "next behavioral anomaly". So to me, the issue seems like a no-brainer. If I want to test, and seem to have a dependency, then the dependees should be tested first. If it seems that there is a natural circular dependency, then I haven't broken the types down properly.
So I'm confused. Constructors that "really" initialize objects detect some kind of errors during compilation, but they make testing harder, are arguably contrary to exploratory programming, and seem to contradict the advice of the designers of the .NET API. Constructors that "sort of" initialize objects are more test-friendly (also more loosely coupled, BTW) and facilitate an exploratory programming style, but defer some kinds of error detection to runtime (as well as incur the runtime time/space costs of such detection and ensuing actions).
So, library users, what do you prefer, and why?
Proper testing either has stub objects which properly emulate a presumption or it has already-tested objects which properly represent their invariant. Exploratory progamming is fine (I use it a lot myself), but if I use bubble gum in my exploratory building then I can't complain when unfortunate things happen. As for the advice of the designers of an particular API.... it sounds to me as if your description of their API indicates that you don't consider their API very highly. It sounds (again, from your description) to be hard to use, easy to user to create a bunch of badly working objects, and hard to debug. I do hope that you've got an alternative to that kind of suffering. Or perhaps I misread your description? regards, Brian