Public and Protected

        Consider the problem of providing a nice user-friendly implementation of good old non-metric weights and measures. The part we looked at in class, with 7 components (tons, quarters, stones, pounds, ounces, pennyweights, and grains) is a bit too big, and I completely forgot about hundredweights at the time, so it should be even bigger. We'll use lengths instead this time. First, cast our mind back to elementary school days and remember the rules:
        12 Lines make an Inch,
        12 Inches make a Foot,
        66 Feet make a Chain,
        10 Chains make a Furlong,
        8 Furlongs make a Mile.
I left out yards because people in the U.S. don't seem to use them very much, and we want to keep it short.
        What should a class contain if it is to represent a length in this style? Obviously six integers to represent the six components, a constructor, a printer, and some things for doing arithmetic. We will also add some "fake" constructors for user convenience; their declarations have the word "static" in them, and they will be explained later. I'll do things a little differently from in class, just for variety.
class length
{ public:
    int miles, furlongs, chains, feet, inches, lines;
 
    length(int m, int fu, int c, int fe, int i, int l)
    { miles=m; furlongs=fu; chains=c; feet=fe; inches=i; lines=l; }
 
    static length feet_inches(int f, int i)
    { length x(0,0,0,f,i,0);
      return x; }
 
    void print(void);
 
    void add(length x);
 
    void multiply(int x); };
As you have seen, sometimes it is OK to put the definition of a method inside the class definition (like the constructor and feet_inches above). The general rule is that this should only be done when the method is very short and simple. One day you'll find out why. For methods that are not very short and simple, declaration and definition are separated in the traditional way.
void length::print(void)
{ printf("%d miles, %d furlongs, %d chains, %d feet, %d inches, %d lines",
         miles, furlongs, chains, feet, inches, lines); }
 
void length::add(length x)
{ int carry;
  lines+=x.lines;
  carry=lines/12;
  lines=lines%12;
  inches+=x.inches+carry;
  carry=inches/12;
  inches=inches%12;
  feet+=x.feet+carry;
  carry=feet/66;
  feet=feet%66;
  chains+=x.chains+carry;
  carry=chains/10;
  chains=chains%10;
  furlongs+=x.furlongs+carry;
  carry=furlongs/8;
  furlongs=furlongs%8;
  miles+=x.miles+carry; }
 
void length::multiply(iny x)
{ int carry;
  lines*=x;
  carry=lines/12;
  lines=lines%12;
  inches=inches*x+carry;
  carry=inches/12;
  inches=inches%12;
  feet=feet*x+carry;
  carry=feet/66;
  feet=feet%66;
  chains=chains*x+carry;
  carry=chains/10;
  chains=chains%10;
  furlongs=furlongs*x+carry;
  carry=furlongs/8;
  furlongs=furlongs%8;
  miles=miles*x+carry; }
        There would probably be a few more methods than that, but these are enough for us. As an example of the use of the class, if we want to add (50 feet, 10 inches) and (37 feet, 3.5 inches), then double the result, we would write:
{ length a(0,0,0,50,10,0);
  length b(0,0,0,37,3,6);
  a.add(b);
  a.multiply(2);
  a.print(); }
This is why the arithmetic methods were declared as returning nothing (void), rather than a length as one might have expected. Instead of taking two arguments and returning a result (which would allow us to write things like a=add(b,c);), these methods take just one argument which they use to modify the object in question (so when we write a.add(b); it effectively means a=a+b;).

        Every method that applies any arithmetic to a length (we've only got two, but in real life there would be at least a couple more) is annoyingly hard to read. When adding 6 inches to 7 inches, we have to be careful to ensure that the result is 1 foot and 1 inch, not 13 inches. Adjusting all six integers to deal with overflows is very simple but repetitive, and obscures the real work being done.
        This process is properly called Normalisation, and it would make perfect sense to implement normalisation as a method in its own right. Then the arithmetic operations would be much clearer:
void length::add(length x)
{ lines+=x.lines;
  inches+=x.inches;
  feet+=x.feet;
  chains+=x.chains;
  furlongs+=x.furlongs;
  miles+=x.miles;
  normalise(); }
 
void length::multiply(iny x)
{ lines*=x;
  inches*=x;
  feet*=x;
  chains*=x;
  furlongs*=x;
  miles*=x;
  normalise(); }
Of course, we'd have to add a declaration of mormalise to the class definition:
  void normalise(void);
and later define it:
void length::normalise(void)
{ int carry;
  carry=lines/12;   lines=lines%12;     inches=inches+carry;
  carry=inches/12;  inches=inches%12;   feet=feet+carry;
  carry=feet/66;    feet=feet%66;       chains=chains+carry;
  carry=chains/10;  chains=chains%10;   furlongs=furlongs+carry;
  carry=furlongs/8; furlongs=furlong%8; miles=miles+carry; }
(As a little aside, even modern processors like a pentium or an alpha, are not always as fast as we imagine. If a programmer is lucky, they can do an addition in a single clock cycle, which means that a 500MHz Pentium III can do 500,000,000 integer additions in a second. Subtractions are just as fast, but multiplications take more than 30 times as long, and divisions even longer still (Alphas don't even have hardware for integer division, a programmer has to write a function to do it!). What all this means is that if speed of execution is important to you, replacing divisions by multiplications, or multiplications by additions, is worth the effort. This statement b=a+a; is almost certain to be much faster than this one b=a*2;.
        Two items of "small print": All that applies more to integer operations that to float operations; with floats the differences still exist, and are still noticable, but are not nearly so large. Also, good compilers know all that, and take it into account; if you write b=a*2; and you are using a good compiler, it will convert it to b=a+a; for you automatically.
        In the light of all that, if speed is important, some improvement may be acheived by replacing
carry=lines/12;  lines=lines%12;
by the mathematically equivalent:
carry=lines/12;  lines=lines-carry*12;
However, it would not be better to write:
carry=(int)(lines*0.833333333333333);  lines=lines-carry*12;
because float operations are generally much slower than integer ones, and less accurate).

Anyway, getting back to the main point, there is nothing wrong with our definition of length, but it is very likely to be used in a way that would fail. So it might just as well be wrong itself.
        All programmers using the class "length" have access to the class definition, and can see what it contains. They know it has six separate integers representing the six components of a length. With this knowledge, a programmer who has already calculated a length and now needs to make it one inch shorter, is very likely to write something like this:
  x.inches=x.inches-1;
Which would work 11 times out of 12 (so might survive testing), but would fail whenever x.inches is zero. Even if the programmer has some brains and realises what normalise is for, and writes instead:
  x.inches=x.inches-1;
  x.normalise();
Would it be any better? Our normalise function was designed to repair things when components get too big, not when they get negative. What would it do when inches is -1? What is (-1)%12? I'm not sure that I accurately remember the answer, and I certainly wouldn't want to rely on it.

When creating a user interface to a system, it is the programmers responsibility to make sure that it works reliably. It should not provide the user with innocent-looking items that can not be safely used.
        We have done a reasonably good job in providing the user with everything he, she, or it needs to use the class safely (that is, the constructor(s), print, and the arithmetic methods). Unfortunately we have done nothing to protect the aforementioned user from the consequences of using the other bits.
        The class is like a vending machine that sells chocolates to the masses. A vending machine has all sorts of lethal components such as high voltages, jagged grinding gears, rotating knives, and eye-ball pokers. Designers of vending machines give them brightly coloured metal covers, which don't just advertise the enclosed chocolates, but also keep the users away from the machine's violent innards. The users are given nice safe buttons to press and flashing lights to gaze at, which provide enough functionality to operate the machine fully.
        We have the buttons and lights (Constructor, print, and arithmetic) which users can use, and the voltages, knives and pokers (the six integers and the normalise function) which users shouldn't touch, but we have no metal cover to enforce that policy.

The Visibility designations public and protected provide a metal cover for a class definition. Any member or method must be designated either public or protected (or private which we'll look at another day). Writing public: makes all subsequent declarations be public; Writing protected: makes all subsequent declarations be protected.
        A public member can be used by anyone, as the name suggests. Public members and methods are the things that the user is supposed to use; the programmer should go to great lengths to ensure that they have no non-obvious effects.
        A protected member can only be accessed from within another method of the class, which means that mere users can not access them directly at all. Programmers can make protected methods really dangerous, because nobody else can use them. You can make protected members (variables) very sensitive and delicate because nobody else can see them. private means almost the same as protected.
        The words "public" and "protected" only have to be stated inside the class definition; they should not be repeated when methods are defined. A better version of our length class would look like this:
class length
{ protected:
    int miles, furlongs, chains, feet, inches, lines;
 
  public:
    length(int m, int fu, int c, int fe, int i, int l)
    { miles=m; furlongs=fu; chains=c; feet=fe; inches=i; lines=l; }
 
    static length feet_inches(int f, int i)
    { length x(0,0,0,f,i,0);
      return x; }
 
    void print(void);
 
    void add(length x);
 
    void multiply(int x);
 
  protected:
    void normalise(void); };
With this definition in force, the normalise method and the six integer variables can only be accessed from within the class itself. This means that the functions length, feet_inches, print, add, and multiply can freely use the variables and call normalise whenever and if ever they want to. That is perfectly OK because we wrote those functions, and the user can't change them. Anywhere else, the compiler will produce a fatal error message if the protected members are even looked at.
        The user can call multiply at any time, and multiply will call normalise, and that is still OK. Even though the user called multiply, we still wrote it, and it can only do things as specified by us, so the user is still properly protected.

Protection also makes classes upgradable. If we had any sense, we would very soon realise that it is very inefficient to store lengths as the six separate components, which occupy probably 48 bytes of storage, and need to be normalised after each operation. We should instead convert all lengths into multiples of the smallest unit (lines) and store them that way, as a single integer. The suer will never know the difference so long as we still print values correctly.
        So version 1.1 of the length class would probably do just that, and look something like this:
class length
{ protected:
    int lines;
 
  public:
    length(int m, int fu, int c, int fe, int i, int l)
    { lines=l+12*(i+12*(fe+66*(c+10*(fu+8*m)))); }
 
    static length feet_inches(int f, int i)
    { length x(0,0,0,f,i,0);
      return x; }
 
    void print(void);
 
    void add(length x)
    { lines=lines+x.lines; }
 
    void multiply(int x)
    { lines=lines*x; } };
 
void length::print(void)
{ int x=lines;
  int l=x%12;
  x/=12;
  int i=x%12;
  x/=12;
  int fe=x%66;
  x/=66;
  int c=x%10;
  x/=10;
  int fu=x%8;
  int m=x/8;
  printf("%d miles, %d furlongs, %d chains, %d feet, %d inches, %d lines",
         m, fu, c, fe, i, l); }
That's certainly simpler (and therefore more reliable) and more efficient, but what has it got to do with upgrades? Recall the example of the programmer who under version 1.0 started playing with the six components. He, she, or it may have written a program containing something like this:
{ length x(0,0,1,4,2,0);
  x.multiply(3);
  x.inches+=1;
  x.normalise();
  x.print(); }
This time the program is correct: normalise certainly works correctly after components have been increased, so nothing wrong here. But, this program would not work with version 1.1, because there is no inches member any more. The system could never be upgraded, and no matter what wonderful and clever improvements you come up with in the future, they will still be using vesion 1.0 until the end of the world. What's worse is that you the programmer will have to maintain version 1.0 as well as your latest versions for as long as you want to keep that customer.
        However, if we had used "protected" and "public" in the first place, the programmer would never have been able to write this program, so the situation would not have arisen. The public members of a class are the users whole view of how that class works. If you make something public, you have to keep it functional even if you completely change the way the class works, for as long as you have any continuing users.
        If any of you have used Java, you will probably have noticed exactly this problem. In the rush to release Java 1.0, the developers made some spectacularly bone-headed decisions about the public parts of their classes (and Java is essentially just a bunch of useful classes), and now the documentation is absolutely infested with descriptions of methods that they no longer want anyone to use, but have to keep valid for the sake of old users. If you use one of those methods, the compiler gives a warning: "Your program uses a deprecated API", but what it really means is "we made a big mistake, but we're blaming you". Large companies can get away with that kind of thing.

Variable members can be troublesome. If you think you want to give users access to a variable but can't be 100% certain that it will always be perfectly safe, even in future versions, make the member protected but add two special access methods as in this example:
class uncertain
{ protected:
    int number;
 
  public:
    void set_number(int x)
    { number=x; }
 
    int get_number(void)
    { return number; } };
The user now still has total access to the variable number, but only through the functions you provided. If at some point in the future you decide that it is too dangerous to ever allow number to be 13, you can simply redefine one of the access methods:
  void set_number(int x)
  { if (x!=13)
      number=x; } };
and there's nothing the user can do about it.


As a final word, "static" still has to be explained. Most methods in a class can only ever be used in the context of an object of that same class. Methods belong to individual objects and have no independent existence. To illustrate this, if I added to the class length a method for amputating an object's feet:
void length::remove_feet(void)
{ if (feet>=33)
    chains+=1;
  feet=0; }
I could never just use the function remove_feet on its own; it would have no way of knowing whose feet and whose chains I'm talking about. remove_feet() would not make sense, but x.remove_feet() does (so long as x is a variable of type length).
        Some methods are different. Particularly constructors. Constructors are supposed to create new objects, so how can you possibly give it the object to work on? Methods like that, that you want to be able to use independently, but are still naturally part of the class, are called static. To make a function static, just put the word static before its return type in all of its declarations. Of course, inside a static function you won't be able to refer to any other members of the class (unless they are also static) unless you provide explicitly an object whose members you want to use.
        The fake constructor feet_inches is a good example of this:
static length feet_inches(int f, int i)
{ length x(0,0,0,f,i,0);
  return x; }
It is supposed to be used to create a new object in a convenient way, rather like a constructor, so a call of it would look like this:
length height_of_joe=feet_inches(5,9);
or even like this:
length x(0,2,4,6,2,1);
blah blah blah
x.add(feet_inches(5,9));

Another example of a static method is an arithmetic method that works the way we expected add to work: not like this a.add(b); but like this a=add(b,c); or even like this a=add(add(b,c),d);. When used like this, add is not particularly attached to any one object. It takes two objects as arguments, and returns one as its result, but doesn't naturally belong to any of them individually.
        We could program it as a perfectly normal function, not part of the class at all:
length add(length a, length b)
{ length x;
  x.lines=a.lines+b.lines;
  x.inches=a.inches+b.inches;
  x.feet=a.feet+b.feet;
  x.chains=a.chains+b.chains;
  x.furlongs=a.furlongs+b.furlongs;
  x.miles=a.miles+b.miles;
  return x; }
because the function doesn't belong to any object it is effectively static, but it doesn't belong to the class at all so it isn't a method (there is no length:: in front of its name) and we didn't have to say static in its declaration. Because it is static, the only way it can refer to any class members is by explicitly naming the object that the member belongs to (the a. b. and x. that appear everywhere).
        Before we discovered public and protected, this kind of declaration would have been enough and we had no need of static. Now, all six of the components are protected, so they can only be accessed from within the class, and add is an independent function, not part of the class at all. A function like the above version of add, that want to be independent of any individual object, but still needs to be part of the class, must be declared as a static method of the class. We would add to the class definition:
static length add(length a, length b);
and after it we'd add:
static length length::add(length a, length b)
{ length x;
  as before
  return x; }
And, annoyingly and confusingly, we would also have to use the full name of the method every time it is used (except inside another method of the same class). So the examples of its use become:
length height_of_joe=length::feet_inches(5,9);
and
length x(0,2,4,6,2,1);
blah blah blah
x.add(length::feet_inches(5,9));


(The End)