Class: Nygaard's Modelling Abstraction or Stroustrup's Data Integrity Container?

From: Universe (universe_at_tAkEcovadOuT.net)
Date: 03/12/04


Date: Fri, 12 Mar 2004 02:46:45 -0500

Here excerpt from an on-line article with the notion of Bjarne Stroustrup,
creator of C++, on what an OO class should be about. I'll comment his views
in some detail later today.
****************************************************************************
****

"Classes Should Enforce Invariants
Bjarne Stroustrup: My rule of thumb is that you should have a real class
with an interface and a hidden representation if and only if you can
consider an invariant for the class.

Bill Venners: What do you mean by invariant?

Bjarne Stroustrup: What is it that makes the object a valid object? An
invariant allows you to say when the object's representation is good and
when it isn't. Take a vector as a very simple example. A vector knows that
it has n elements. It has a pointer to n elements. The invariant is exactly
that: the pointer points to something, and that something can hold n
elements. If it holds n+1 or n-1 elements, that's a bug. If that pointer is
zero, it's a bug, because it doesn't point to anything. That means it's a
violation of an invariant. So you have to be able to state which objects
make sense. Which are good and which are bad. And you can write the
interfaces so that they maintain that invariant. That's one way of keeping
track that your member functions are reasonable. It's also a way of keeping
track of which operations need to be member functions. Operations that don't
need to mess with the representation are better done outside the class. So
that you get a clean, small interface that you can understand and maintain.

Bill Venners: So the invariant justifies the existence of a class, because
the class takes the responsibility for maintaining the invariant.

Bjarne Stroustrup: That's right.

Bill Venners: The invariant is a relationship between different pieces of
data in the class.

Bjarne Stroustrup: Yes. If every data can have any value, then it doesn't
make much sense to have a class. Take a single data structure that has a
name and an address. Any string is a good name, and any string is a good
address. If that's what it is, it's a structure. Just call it a struct.
Don't have anything private. Don't do anything silly like having a hidden
name and address field with get_name and set_address and get_name and
set_name functions. Or even worse, make a virtual base class with virtual
get_name and set_name functions and so on, and override it with the one and
only representation. That's just elaboration. It's not necessary.

Bill Venners: It's not necessary because there's one and only
representation. The justification is usually that if you make it a function,
then you can change the representation.

Bjarne Stroustrup: Exactly, but some representations you don't change. You
don't change the representation of an integer very often, or a point, of a
complex number. You have to make design decisions somewhere.

And the next stage, where you go from the plain data structure to a real
class with real class objects, could be that name and address again. You
probably wouldn't call it name_and_address. You'll maybe call it
personnel_record or mailing_address. At that stage you believe name and
address are not just strings. Maybe you break the name down into first,
middle, and last name strings. Or you decide the semantics should be that
the one string you store really has first, middle, and last name as parts of
it. You can also decide that the address really has to be a valid address.
Either you validate the string, or you break the string up into first
address field, second address field, city, state, country, zip code, that
kind of stuff.

When you start breaking it down like that, you get into the possibilities of
different representations. You can start deciding, does it really add to
have private data, to have a hierarchy? Do you want a plain class with one
representation to deal with, or do you want to provide an abstract interface
so you can represent things in different ways? But you have to make those
design decisions. You don't just randomly spew classes and functions around.
And you have to have some semantics that you are defending before you start
having private data.

The way the whole thing is conceived is that the constructor establishes the
environment for the member functions to operate in, in other words, the
constructor establishes the invariant. And since to establish the invariant
you often have to acquire resources, you have the destructor to pull down
the operating environment and release any resources required. Those
resources can be memory, files, locks, sockets, you name it-anything that
you have to get and put back afterwards."

Excerpted from:
The C++ Style Sweet Spot
A Conversation with Bjarne Stroustrup, Part I
by Bill Venners
October 13, 2003
http://www.artima.com/intv/goldilocks4.html



Relevant Pages