Internal and External State - ProjectStow/ClassExamples GitHub Wiki

Internal vs External state

Basic concepts: internal and external state.

When working in C++ and defining member variables what we are doing is defining the internal state of an object. That state lives with the object and might be exposed (using the public keyword) or not. Sometimes the intent of an objects is to provide nothing more than a container for public information and the notion of internal and external does not really exist. Generally however an object exhibits some form of behavior (via the methods it implements) which functions by using the internal state. Allowing other sections of code outside the object to directly access this internal state is bad for a number of reasons. The general issues is a number of different types of coordination, say an object has a notion of its’ color stored in a member called simply “color”. One obvious coordination issue is what does value of “color” look like ? Is a a name like “red”? A RGB value like “FF0000”? or something else? By sharing this internal state we cause the external context to rely of the internals of our object, might makes it much harder for both to evolve.

Another coordination issue related to the fact that there is no way for our object to act if the “color” member is changed. It might be that our objects needs to tell some other object when it needs to be repainted. Thus is our objects was “blue” and another context just changes out color to “red” there is no way to ask to be repainted… some random time in the future we might be repainted and only at that time the new color used.

Here enters the notion of external state. External state is what other objects (and consumers) think the object looks like, not how it is actually implemented internally. Generally we call the external state the properties of the object (although sometimes they are called the external attributes). Let us now say what we want the object to have a property called “color”. Also how about a few more properties say “RGBcolor”, “RedColorValue”, “GreenColorValue”, “BlueColorValue”. All five properties now relate to the color of the object. In generic C++ we would write a number of public methods to reflects this external notion of state (string color(), setColor(string), int redColorValue, setRedColorValue(int), RGB rgbColor, setRGBColor(RGB) etc.). Each of the member functions would then be written to correctly update and interpret the information. Let’s take the setColor(string) as a simple example. Generally the member functions used to work the properties as called accessors. In general there a "read" accessors and "write" accessors, although other types do exist (a reset accessor for example).

When implementing the assigned part of a property (.e.g. set) there are is basic pattern:

  1. Validate the input
  2. Translate to internal form
  3. Make internal state changes and updates
  4. Notify concerned parties

So for implementation we first must ask what is in the string being passed into the method (member function). This is what external presentation of the data do we understand ? By understanding various form with allow external consumers to work in ways most natural to themselves and help future proof the software. In the with might say string right now could be a hex number six characters long (“FF0000”, a color name (“RED”), or three integer values separated by comas (“255,0,0”). For our purposes here we will say the string color() function always returns then hex form (although we could also implement string color(format) variant to return the other form).

Implementation needs to verify the form is known and if valid go ahead and translated it to whatever internal form is being used. From the outside we have no idea what this is. Likewise we do know or need to know what other things may need to happen.

Another key thing about properties is they might well be readonly or derived information. For example we could have chosen to only have redColorValue(), greenColorValue(), and blueColorValue() and not provide an assignment equivalent. Indeed this might event be wise unless is is desirable to only have one channel the object color change at a time.

For example as the object is set to the color “FF0000” (red) and you want to change it to “0000FF” (blue).

O.setRedColorValue(0) // object becomes black (“000000”) O.setGreenColorValue(0) // object remains black O.setBlueColorValue(0) // object finally becomes blue (“0000FF”)

Likely this would happen so fast you might see a black flash, but you can image the potential problems.

So using generic C++ we can see there are a number of implementation patterns we can use to defined and implement properties. Fortunately for use the Qt framework as direct support for defining and implementing properties! The overview page can be found here https://doc.qt.io/qt-6/properties.html. More on Qt properties in the next post.