Bookmarks:

In object-orientation, an object can be considerable immutable even if it... changes.

Learning a complex concept tends to be better absorbed if we divide the concept into small parts.

For example, when we begin to learn English, we are taught that to refer to something that happened in the past, we must use past verbs to make affirmations or use the modal verb did or did not to ask questions or denials. This is the verbal tense Past Simple.

Example: "I saw this movie".

Then, as you begin to study the language more, you discover that there are many other ways of expressing something that has occurred in the past. For example, the use of verb tense Present Perfect.

Example: "I have seen this movie".

Here we see the use of the modal verb to have and the use of Past Participle of the verb to see.

Both sentences say the same when we translate to Portuguese, for example, but the second sentence can be considered more correct than the first one  you only discover this after you learn the Present Perfect. But this is not an English article, so let's go back to object-orientation.

This introduction is to show you that we must first learn a concept in its simplest form; then we improved.

When you've learned about immutability you may have thought that an object is immutable if, after it is created, nothing is changed inside it or that the object always returns the same information when a method is called.

Well, that is not so simple.

Unlike functional languages, where everything is immutable by default, in object-orientation this concept may be broader.

Let's take a look in some concepts.

A class that represents a file could be immutable in two ways:

type TFile = class private FFilePath: string; FStream: IDataStream; public constructor Create(const FilePath: string); function Stream: IDataStream; end; implementation constructor TFile.Create(const FilePath: string); begin FFilePath := FilePath; end; function TFile.Stream: IDataStream; begin if not Assigned(FStream) then FStream := TDataStream.New(FFileName); Result := FStream; end;

In the code above, the TFile.Stream: IDataStream method will always return the same value read on the first run.

The object is immutable and constant.

But, what if we change the method like below, the class will continue been immutable?

function TFile.Stream: IDataStream; begin Result := TDataStream.New(FFileName); end;

Yes, for sure.

Although the result of the method may be different for each call  the contents of the file can be changed by another process  the object would remain unchanged because its state ( FFilePath attribute) has not been changed.

It is immutable, but not constant.

The same concept applies to content coming from a Database, Website, etc.

Can a list of objects be considered immutable if we add items after it is created?

Let's take a look in this code:

type TDataParams = class(TInterfacedObject, IDataParams) private FList: TInterfaceList; public constructor Create; class function New: IDataParams; overload; destructor Destroy; override; function Add(Param: IDataParam): IDataParams; overload; // ... end; implementation { TDataParams } constructor TDataParams.Create; begin inherited Create; FList := TInterfaceList.Create; end; class function TDataParams.New: IDataParams; begin Result := Create; end; destructor TDataParams.Destroy; begin FList.Free; inherited; end; function TDataParams.Add(Param: IDataParam): IDataParams; begin Result := Self; FList.Add(Param); end;

The TDataParams class encapsulates a list of TInterfaceList .

At each inclusion of a new item, the in-memory persistence of the objects is delegated to this internal list.

Do you think we're changing the object state ( FList )?

We are not.

The reason is that we are not redefining FList . We are not creating a new list.

A list of items is being created in memory  memory blocks  but the initial address of FList remains intact.

Also, FList is a secondary attribute, so we could even redefine this attribute without being in disagreement with the principle. But, if the list instance were passed in the constructor, then we could not redefine the object because it would be considered as a primary attribute.

If even after some internal or external changes to the object, it is still considered immutable, how do we know if we are not violating the principle of immutability?

Simple: If the state of the object, ie., its primary attributes, is not changed/redefined, then it is immutable.

Once an attribute is instantiated, it can not have its memory address changed. These attributes will be initialized in the constructor of the class and can never be reinitialized.

Your object must be faithful to arguments passed in the class constructor, however it is free to work and respond to whatever you want in your methods.

Immutability, in object-orientation, is not about internal or external changes to the object, but about not changing the primary state of it.

Do not confuse data with object state.

So, we need to work with these concepts in mind.

See you.