State Encapsulation - Spicery/Nutmeg GitHub Wiki
Overview - Basic Concept
A key design principle in object-oriented programming is state encapsulation. It is a key technique for stateful programming that prevents unintentional updates of shared store. But what does that actually mean in practice? This page explains what it is and how it works in Nutmeg.
The central concept is that the mutable state of an object X is 'owned' by X. The only way to modify that object's state is to have a handle on X. The simple interpretation of this is that if a mutable object Y is part of the state of X, it cannot be exposed by the public methods of X and is permanently hidden away.
For example, the following class exposes the slot (a.k.a. field) clubMembers
and so its state is not encapsulated:
class Club:
slot clubTitle
slot clubMembers = MutableList()
def ^addMember( m ): ^clubMembers.add( m ) end
def ^countMembers(): ^clubMembers.length end
end
We can easily discover it is not encapsulated like this:
club := Club()
club.add( Member( 'Lucky Jim' ) ) ### class Member defined elsewhere
assert club.countMembers == 1 ### passes
mlist := club.clubMembers ### get privileged access to the inner state of club!
mlist.clear() ### delete all the members of the list ... but this will damage the club membership!
assert club.countMembers == 1 ### FAILS - the club was altered without any direct access to the object, only its internals.
To encapsulate the state of the object we need to prevent the 'outside world' being able to access the clubMembers slot. It is not enough to limit the visibility of the clubMembers variable, although that is a good start, we also have to protect against 'reflection'. (N.B. Nutmeg provides a highly structured form of reflection that supports traceability and garbage collection and not the usual unstructured reflection.) The local
modifier, when applied to the clubMembers slot, not only limits the visibility of clubMembers to the scope of the class but protectively marks the slot.
class Club:
slot clubTitle
local slot clubMembers = MutableList()
def ^addMember( m ): ^clubMembers.add( m ) end
def ^countMembers(): ^clubMembers.length end
end
Now our attempt to subvert the state of Club fails.
club := Club()
club.add( Member( 'Lucky Jim' ) ) ### class Member defined elsewhere
assert club.countMembers == 1 ### passes
mlist := club.clubMembers ### get privileged access to the inner state of club!
### MISHAP: Reference to unknown identifier
### VARIABLE: clubMembers
Accommodating Dependencies
TO BE DONE
- Key idea - store ownership
- To make this work - explicit dependencies
- RW views considered questionable - need to maintain relationship
- Callables - must package the items they operate on