Immutable objects

Posted by Peter Judge on 08-Sep-2017 12:12

I'm working through some stuff where I have a registry of services. Each service is put into the registry using a Put() method and stored as an object. I'd like that only the registry be able to modify the service objects. I have a GetService() method which returns the registered instance. I'd like that returned instance to be immutable (ie not change the values in my registry). I can (I suppose) return a clone of the registered object, but that becomes painful when the service has (a) collection(s) of child objects, which themselves may have children. Now I have to iterate all the way down, when I want to return a single instance. This seems ... painful.

I suppose I could be "smart" and use temp-tables to back the object properties (so just have the properties etc be a strongly-typed facade on temp-table fields) but this has it's own problems. Making individual objects immutable is easy enough ig you make all properties read-only and pass an entire object's definition via the constructor. I'm looking for "sometimes mutable" objects.

Just wondering what your (collective) thoughts on immutable objects (and how to implement in ABL cheaply/simply) in general, and on this topic are.

All Replies

Posted by Tim Kuehn on 08-Sep-2017 13:04

My thoughts:

If the service's behavior doesn't change after a prior call (ie does not persist state) then the implementation is already immutable.

If the service persists some state after it's called and that state could/will affect the behavior of follow-on calls, then you need to make a copy of the service and return the copy -or- separate out the functionality which persists the service's state and give the calling code a copy of that while retaining the state-free part of the code as the core of the service.

Posted by Peter Judge on 08-Sep-2017 13:14

Sorry, maybe I should have been clearer.
The objects in question are basically service definitions (ie name, version, options, etc). I don’t want someone getting a reference  to a service and changing something, since that means that it changes for anyone else who asks for the service definition.

Posted by on 08-Sep-2017 13:22

If you can make the registry the factory of said objects you can inject an 'update password' in their constructors and then on setters methods also send the password, hopefully no one will be able to hack your system ;)

Sent from outer space

Posted by Thomas Mercer-Hursh on 08-Sep-2017 13:27

I'm wondering a bit why you are focused on immutability as a concept.  It seems to me that a particular type of object has certain behavior.  If that behavior includes only read-only requirements, then it is provided only with read only methods, although that implies setting through the constructor, which I am not nuts about unless it is very simple.  If it needs both read and write methods, but it should only be writeable up to some point where it becomes read only, like a Client Principal, the provide a switch which disables the write methods once the switch is thrown.  If that is true for outside users, but not for the creator, then provide a key protected method for flipping the switch back.  I.e., the object needs to have whatever behavior it needs to have and you need to provide methods which implement that behavior and not provide any other methods which do something not in the behavior set.

Posted by ntwatkins on 08-Sep-2017 13:29

If the objects are supposed to be immutable, how does the registry modify the service objects?

Posted by Peter Judge on 08-Sep-2017 13:50

Maybe I should state the requirement slightly differently.
The registry – and only the registry – should hold the canonical data.  To change the registry, a set of Put() and Remove() methods are provided.
A caller can retrieve the service data via Get() methods. The caller will receive a Service() object. If changes are made to the object returned, the changes must not affect the registry data. Immutable objects are one way to prevent changes by the caller.
Cloned objects are another, although this presents its own set of challenges (deep clones).
For instance, a service has a version. Changing the version (object ref) on the service should not change the version in the registry.

Posted by ntwatkins on 08-Sep-2017 14:09

How do you determine if a call to a Put() or Remove() is valid?

Posted by jmls on 08-Sep-2017 14:46

what I think you are describing is reactive programming (see for an angular 4 version)

Core tenets:

State is a single immutable data structure

Actions describe state changes

Pure functions called reducers take the previous state and the next action to compute the new state

State accessed with the Store, an observable of state and an observer of actions

Basically, coding to events. A component *does not* mutate an object : it sends the existing object to a reducer which creates a new object, and mutates that object according to the reducer function. A new state is then broadcast , and any interested subscriber gets the new state.

The idea of the store is to have one and only one single place of truth, which means all the objects are immutable, and the only way to change anything is to recreate everything as a whole.

Posted by agent_008_nl on 11-Sep-2017 05:01

For a bit of background on reactive programming read "out of the tarpit":

(named in f.e.  "Learn to Build Reactive Apps with Angular" also). Out of the tarpit is one of my favourite documents about software development.

Posted by Peter Judge on 11-Sep-2017 09:59

I assume that the intent of a caller making Put() and Remove() calls into the registry is to modify the registry. Assuming valid data is passed in, anyone can modify the contents.

I cannot assume that when a caller has a reference to a service def object and changes properties on that instance, that they intend to change the canonical values..

I think the right answer may be to return a new instance every time . But I'm concerned about performance of cloning (especially if there are deep/large object graphs)

Posted by agent_008_nl on 11-Sep-2017 12:06

Maybe your question about changing immutable objects still isn't clear, even when assuming valid data is passed in? :-)  

Posted by jquerijero on 11-Sep-2017 13:59

Just playing devil's advocate;

"I cannot assume that when a caller has a reference to a service def object and changes properties on that instance, that they intend to change the canonical values."

I don't think you can also assume the opposite. Some might expect it to change when modified.

Posted by Peter Judge on 11-Sep-2017 14:06

Fair enough.  Should I generally care that the object was changed? (In this case I think that I do. )
If the object was immutable it’d be clear that they’re not expected to make changes this way.

Posted by jmls on 11-Sep-2017 14:06

so that's the whole point of the reactive coding. You dispatch the original object with the action and data and the reducer creates a new object based on the original, action and data. This is then stored and the new value emitted

So there is a continuous stream of events and new versions of the object being monitored. This also allows you to build a "time machine" (a hook can take this stream of new versions and stack them) which allows you to easily add undo/redo capabilities to the system

the important take away is that there is only one place of code that can "modify" (create a new version) of  the object, and one "source of truth"

Posted by Thomas Mercer-Hursh on 11-Sep-2017 14:24

I don't think you can also assume the opposite.

I don't know that one can assume one or the other ... it should be a part of the rules for the object type.

Posted by agent_008_nl on 12-Sep-2017 00:07

Maybe some helpful info can be found in redux docs f.e.

This thread is closed