From: maxtal@extro.ucc.su.OZ.AU
Newsgroups: comp.lang.c++
Date: 18 Jul 92 10:19 MDT
Subject: Re: many set/get member functions in a 
Nf-ID: #R:1992Jul08.121838.13948@jho.com:2043735141:1992Jul18.061906.29676@ucc.su.oz:-850869296:001:8090
Nf-From: extro.ucc.su.OZ.AU!maxtal    Jul 18 10:19:00 1992


In article <rmartin.711379395@thor> rmartin@thor.Rational.COM (Bob Martin) writes:
>maxtal@extro.ucc.su.OZ.AU (John (MAX) Skaller) writes:
>
>
>|If, however, the SEMANTICS 
>|that there be an unconstrained 'variable' in the class,
>|then making a public variable or function returning a reference
>|ensures AT COMPILE time that this contract is kept by the
>|class. 
>
>It seems very unlikely to me that any properly thought through
>abstraction would demand that a variable be exposed through its
>interface.  

	Yes. And no.

	Yes: when I think up abstractions, they're usually
	of the form that has no unsconstrained variables.

	No: in practical programming, many things are 
	quite concrete, and the program might be a one-off.
	So a simple struct is often the easiest way.
	Sometimes *I* claim, it is correct too.

>
>An object is an encapsulation of state and behavior, exposed through
>an interface.  The interface has the task of insuring that the
>invariants of state are maintained.  If internal variables can be
>manipulated from the outside, these invariants may be violated without
>the object's knowledge, leaving the object in an invalid state.

	I do not disagree with this philosophy, although I
never think in terms of 'behaviours'.

	The interface is but ONE aspect of the semantics.
The semantics, including the interface, should be immutable.
If I could also specify a class invariant, or even better,
some axioms, THAT would be the semantics and it would be
immutable.

>
>"But", you say, "I have a variable which has no invariants, so it is safe
>to expose this variable to my clients."

	No, I don't say "it is safe". On the contrary, I say
its exposure in C++ is one of the few ways that one can also
specify semantics completely and get a guarrantee that
the semantics cannot be violated.
 
>
>Is it indeed?  Let me tell you a little story.
>
>I once wrote an object oriented application for manipulating icons on
>a screen.  I created a "Point" class which encapuslated a single
>cartesian coordinate.  In my naivete I thought, as you think now, that
>I should expose the 'x' and 'y' variables.  

	Hold on, dont jump to conclusions! I would NEVER advocate
that the x and y coordinates of a point be exposed publically.
I would ALSO say set_x and set_y functions were naughty.
I would require you to set BOTH coordinates simultaneously.

>After all, I did not want
>to have to write a set of accessor functions, that was too much work!
>Little did I know!

	I agree you did it wrong: but NOT for the reasons you
outline below. I will explain why.
>
>Much later, when the project was nearly complete, I decided to add the
>concept of a constraining grid to the screen.  I am sure you have seen
>constraining grids, they separate the screen into a grid with a
>spacing of 5-10 pixels or so, and force any positional change of any
>object on the screen to align to this grid.  This makes it easy for
>the user to line up his icons in staight horizontal or vertical rows.
>
>Anyway, I realized that this would be remarkably simple to do, if I
>created the concept of a ConstrainedPoint, derived from Point.  This
>new abstraction would automatically adjust its coordinates to the
>grid.  The rest of the application could remain blissfully ignorant of
>the contraining grid. But alas, it was not to be.  All through my code
>there were direct accesses to the x and y variables of class Point.
>THere was no way for me to insert the constraint in a single place.  

	But there is. You just didn't think of it.

	class ConstrainedPoint : private Point {
		ContstrainedPoint(int x, int y);
	};
 
>
>Thus, I created bad situtation for myself.  I had to search through
>the code, finding every use of x and y, and apply the contraint
>locally.  Worse, I created a maintenance nightmare for the company,
>since now the maintainer must always remember that when they
>manipulate an x or x they must check for, and apply, the contraint.

	Absolutely necessary for you to do this running through
the code. No way out. You HAVE to change you program
to use constrained points where desired. Here's why:

	I also used your point class.

	I dont ALWAYS want constrained points.

	I have rectangles: (ICONS for example) and have
	cached all 4 corners.

	Now assume you had use set_x and set_y.

	Suddenly, my corners are all wrong. (Only the left
corner of an icon snaps to the grid, the others can't because
the sieze of the icon is fixed).

	But if you used the public variables YOU COULD NOT
DO THIS NAUGHTY CHANGE TO THE SEMANTICS AND DESTROY MY CODE.
>
>Blech!
>
>I don't want to hear that the semantics of Constrained_Point were
>different than the semantics of Point, and so the application should
>have been changed at every place which used Point.  

	Well, that is exactly what I am telling you must be done.

>That argument is
>absurd.  I didnt want the rest of the application to know about
>Constrained_Point.  

	But I have shown you that SOME parts of the application
RELY ON THE POINTS NOT BEING CONSTRAINED.

	Your idea that you can magically change the semantics 
by using polymorphism is absurd. 

>I wanted the semantics of contrainment to be
>hidden.

	I'm glad you used a public variable because that 
PREVENTED YOU HIDING THE SEMANTICS and stuffing up MY
piece of code.
>
>Also, I don't want to hear that I should have anticipated the need for
>contrainment.  That is a useless argument too.  If OOP forces me to
>think of everything in advance, then it is a worthless concept.

	Yes, I agree. In class based languages like C++
the requirement is alleviated: you MUST GET THE SEMANTICS
EXACTLY CORRECT AND NOT DEVIATE FROM THEM, and then if
you obey the above rule you are allowed to derive
new classes.

	IF YOU CHANGE THE SEMANTICS (just like if
you change the interface) THEN YOU MUST REEXAMINE EVERY
USE. It is best to add a NEW unrelated class sometimes,
since that leaves all existing code working, esepcially
MY piece of code that relied on points having unconstrained
coordinates.
>
>But fortunately, when properly applied, OOP does not force you to
>anticpate every need of the application.  By hiding semantics, you can
>create a system which is flexible enough to withstand many
>unanticipated changes.
>

	NO. You hide the IMPLEMENTATION. 
	You hide irrelevant detail.


	Constrained points are NOT semantically equivalent
to unconstrained ones.

	HAD you used Constrained points FIRST and then derived
Unconstrained ones from them as a special case, you would
have had no problem.

	Since you did not have the foresight to do this,
you had to rework your code. This is as it should be,
indeed, as it must be, and the fact that it ISNT in practical
languages is a DISADVANTAGE of the language.

	In short: OOP rewards foresight.

	In C++ especially, you really MUST get the design
exactly right and stick to it. In C++ there is a
MASSIVE shift of effort from programming to design.
Your reward for working under such stringent constraints
is run-time correctness.

Each weakening of the constraints leads to  decreased
ability of the compiler to provide guarrantees.

Thus, in smalltalk, you can design anything, but only
your customers know if it works. At least in C++
the COMPILER knows something, when a program
has been compiled *I* have some sense of security
I could never have in sta.

I would like to see better language support for
semantics: Eiffel has shown one way.

Then my cached points would have invariants:
"Distance between two top points equal width of rectangle"
and I could detect at run-time that you broke your
contract with me to provide unconstrained points
EVEN if you had set_x and set_y methods.

As it happens, a public variable would provide that very
guarrantee even better (although I would not utilise
that feature in the case of a point)


-- 
;----------------------------------------------------------------------
        JOHN (MAX) SKALLER,         maxtal@extro.ucc.su.oz.au
	Maxtal Pty Ltd, 6 MacKay St ASHFIELD, NSW 2131, AUSTRALIA
;--------------- SCIENTIFIC AND ENGINEERING SOFTWARE ------------------

Newsgroups: comp.lang.c++