|
Boost Users : |
From: Brian Allison (brian_at_[hidden])
Date: 2006-09-12 07:06:39
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
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net