Undermining object integrity . . .

The Strange Demise of Object Constructors

Conrad Weisert
May 1, 2014

This article may be circulated freely as long as the copyright notice is included.

A New idiom

We're seeing a peculiar idiom in object-oriented programming, perhaps encouraged by the ease of coding accessor functions (now called properties) in C#. We expressed concern about this trend back in December, and it has only become more common since then in actual applications, in textbooks, and in courses.

Programs are no longer initializing newly created objects through constructor parameters. Instead they're going through a multi-step process like this:

  1. Create an empty object with zero values and null references, via a parameter-less default contructor.

  2. Then initialize the member data items one at a time through public set accessors.

Some obvious difficulties:

Indeed, this technique discards many of the virtues of object-orientation. It's as if we were programming in Fortran, but harder to read.

Hiding Internal Representation

Suppose we define a simple class for representing temperatures:

  class Temperature   {
        double value;   //  What are the internal units?
        .
     public . . . 
        .
   } 

There's only one member data item, so we don't have to worry about incompletely initialized objects. But now, users of the class will want to do things with temperatures. They may even wish to display temperatures on a screen or print them on a report for users. To cater to those users the output may need to be in degrees Kelvin, in degrees Celsius, or in degrees Fahrenheit.

No problem: We'll just provide three public accessor funtions to retrieve those quantities from a Temperature object. One of those accessor functions will return the internal representation, the private data item value, and the other two will return the appropriate simple function of that value.

Of course, users of the Temperature class should not know which is the pure accessor function and which ones perform units conversion. So far, so good.

Should It Work Both Ways?

Now if we can retrieve a temperature in degress Fahrenheit, should we also be able to set a temperature to some Fahrenheit value? C# makes it very easy to do so. All we have to do is code the appropriate inverse conversion in the set clause of a property. Indeed a programmer can provide the whole repertoire of gets and sets for all three kinds of Temperature unit in just a few minutes.

Where does that leave our traditional object constructor? Do we still need one? A single-parameter constructor knows what its argument is and how it relates to the internal object representation. "Pick one," we advise the class designer, "the most common representation among our user community, the representation we want to encourage as our standard."

"'Hold on, there!" a perceptive student may exclaim, "You told us we're not supposed to know the internal data representation. Now you're telling us that one particular representation, the parameter to the constructor, has a special preferred role. Furthermore, it seems very likely that the internal representation will have been chosen to match that constructor parameter (or vice versa)."

Yes, indeed, there's a lack of symmetry there. But that's all right. A small number of programs that create Temperature objects can be expected to know (or find out) the constructor specifications, while a larger number of programs that retrieve a temperature value for reporting or display purposes should be free to choose their units to suit the expected audience. Note that very few if any programs should need to retrieve a Temperature value for use in computations, since a sensible Temperature class presumably provides all the arithmetic operators and functions needed to work directly on the object.

So, except where there's a strong reason otherwise, avoid public set operators or write accessors for private member data. Provide constructors that initialize the whole object with consistent data values. If an object can't be immutable, make necessary changes to it only through disciplined member functions that preserve consistency and validity.


Last modified May 8, 2014

Return to Home page.
Technical articles