Blog

All Blog Posts  |  Next Post  |  Previous Post

Object Pascal: Immutable State

Tuesday, April 17, 2018

Photo by Morgan Harper Nichols on Unsplash

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

Introduction

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.

Concepts of Immutability

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.

External content

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.

Content in Memory

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.

Immutability of the State

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.

Conclusion

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.



Marcos Douglas B. Santos




This blog post has received 4 comments.


1. Wednesday, April 18, 2018 at 12:14:48 AM

I found this article very confusing.

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

No, it can''t. You then go on to try to prove that it can by creating an object that hides a list from the outside. Unfortunately, you do not explain what this object is intended to do nor show its complete code, meaning we cannot determine whether it is immutable or not. If its behavior depends on what''s in that list, then it is NOT immutable.

In fact, think of a parallel operation. What about two threads attempting to add objects to that list at the same time? If you have to worry about locking, you''re not dealing with an immutable object. What about hashing? If hashing depends on what''s in that list, it''s also not an immutable object.

You also go on about memory addresses, which have nothing to do with being immutable or not.

I feel this article only serves to muddy the waters regarding what immutability, which should be a simply subject.

Joseph


2. Wednesday, April 18, 2018 at 6:17:26 PM

When I think of immutable I think not of the inner object but of the public methods that are exposed. Changes can easily occur inside the object, but the interfaces should remain static. That is not to say that you cant later add an additional interface, its just that the first one can''t change. This is something that Microsoft partly gets right in some of their API''s, but other companies (anyone remember Crystal Reports) gets horribly wrong.

Steven


3. Friday, April 20, 2018 at 10:14:22 AM

Was that a typo: "Can a list be considered mutable if we add items..."? Did you mean immutable?

If you can change the contents of a publicly acccessible list, it is indeed mutable (not immutable). If the list is purely private, and only internal state is modified, then the object is not necessarily mutable.

Rudy Velthuis


4. Friday, April 20, 2018 at 3:56:05 PM

@Rudy Velthuis

You''ve got the idea.
And you''re right, that was a typo. Thanks.


Marcos Douglas B. Santos




Add a new comment

You will receive a confirmation mail with a link to validate your comment, please use a valid email address.
All fields are required.



All Blog Posts  |  Next Post  |  Previous Post