Quantcast
Channel: TMS Software
Viewing all articles
Browse latest Browse all 1093

Object Pascal: Immutable State

$
0
0

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 mutable 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.




Viewing all articles
Browse latest Browse all 1093

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>