Object Immutability: The Basics

Object Oriented Programming (OOP) states that objects must handle the state and behavior of your application.

In this post, I am going to discuss what an object state means and how objects should behave in a concurrent environment.

TRY IT YOURSELF: You can find this post source code here.

Object’s Immutability Series

Object State

Well, state is data saved somewhere that means something in a defined context.

In OOP, the Object state is the properties values it keeps, for instance, let’s see this Person class:

class Person{
 String name;
 String address;
 LocalDate birthDate;
}

The state of the Person class is….. well, a class doesn’t have state.

NOTE: You might think that static variables are the class state, and you are right, however, try to be clear when you talk about object state and class state.

Now, let’s fix the language: The state of any object of the Person class is defined by his name, address and birthDate.

You can create multiple Person objects holding different states:

Person daniel = new Person();
daniel.name = "Daniel";
daniel.address = "Daniel's Address";
daniel.birthDate = LocalDate.of(1988, 9, 8);

Person rafael = new Person();
rafael.name = "Rafael";
rafael.address = "Rafael's Address";
rafael.birthDate = LocalDate.of(1970, 9, 8);

Something looks weird here, doesn’t it?. Of course, this class is poorly designed:

  • You access the state directly, from everywhere, to query and set values. Encapsulation is broken.
  • The Person class doesn’t have any behavior, it means, that should really be a class after all?. Single Responsibility Principle could be broken
  • Who is in charge of Person creation? Seems like Person class is not…..

TRY IT YOURSELF: You can find this source code here.

Encapsulating the Object State

Let’s improve Person class:

class Person{
 private String name;
 private String address;
 private LocalDate birthDate;

 public void setName(String name){
   this.name = name;
 }

 public void setAddress(String address){
   this.address = address;
 }

 public void setBirthDate(LocalDate birthDate){
   this.birthDate = birthDate;
 }

 public String getName(){
   return this.name;
 }

 public String getAddress(){
   return this.address;
 }

 public String getBirthDate(){
   return this.birthDate;
 }
}

Looks better:

  • Person class owns methods to update and query his state.
  • You cannot access the state directly.

However, there are some disadvantages:

  • More code to maintain.
  • Side effect flow, for instance, you send the Person object to a method who change its state without notice.
  • Concurrent access to a Person instance, could be problematic.

About the concurrent access, let’s see this example:

Two thread accessing an object

Concurrency is an interesting case. We have two threads sharing the same object, in this case, Daniel. The init address value was Street 25, Thread1 queries the address, later, Thread2 updates the address to after perform some specific Service2 logic. However, Service1 queries again the address, getting the new updated value.

Is this behavior right? well, that depends on your business rules, but, I can tell you that something might not be right…..

Running the Example

We built an example to test this challenge. You can find the source code here.

The following is the result for the first run:

First run of mutable objects in a concurrent environment

As we can see, Service1 queries the address and in some iteration it found “Street 70”, due to Service2 changed that value from its initial “Street 25”.

This is for second run:

Second run of mutable objects in a concurrent environment

That was the same scenario, and, as we can see, it fails before.

NOTE: Remember, this is a concurrent environment, you cannot predict easily when this is going to fail.

To fix this behavior, shouldn’t be allowed to modify Daniel object after it was created. That is call Object Immutability.

Creating a Person immutable class

Well, the easy way is to remove the setters and add a constructor on Person class:

class Person{
 private String name;
 private String address;
 private LocalDate birthDate;

 public Person(String name, String address, LocalDate birthDate){
  this.name = name;
  this.address = address;
  this.birthDate = birthDate;
 }

 public String getName(){
   return this.name;
 }

 public String getAddress(){
   return this.address;
 }

 public LocalDate getBirthDate(){
   return this.birthDate;
 }
}

Now, you cannot modify a Person object, you only can set his values in instantiation time. So, what if you need to update a value without setters?, let’s add kind of setters:

class Person{
 private String name;
 private String address;
 private LocalDate birthDate;

 public Person(String name, String address, LocalDate birthDate){
  this.name = name;
  this.address = address;
  this.birthDate = birthDate;
 }

 public Person setName(String name){
   return new Person(name, this.address, this.birthDate);
 }

 public Person setAddress(String address){
   return new Person(this.name, address, this.birthDate);
 }

 public Person setBirthDate(LocalDate birthDate){
   return new Person(this.name, this.address, birthDate);
 }

 public String getName(){
   return this.name;
 }

 public String getAddress(){
   return this.address;
 }

 public LocalDate getBirthDate(){
   return this.birthDate;
 }
}

Any time you need to change a value on Person, Person is going to create a new object, the concurrency now looks like this:

Immutable Person on a concurrency environment

Now, the Person objects are thread safe. Each thread sees the right information.

Running the Example

We built an example to test this fix. You can find the code here.

The following is the result for the run:

Run of immutable objects in a concurrent environment

As we can see, doesn’t matter how many times you run it, you will get the same result. This is a predictable system.

Is this memory consuming? well, yes, it is, however, you are saving a lot of troubles in concurrent environments.

Final Thought

Systems were concurrency is important, should be careful about how the system state is used. Immutability is a great tool to start, removing some of those state problems.

However, doing immutable systems is hard, for instance, what if you have a immutable object referencing a mutable one?

In the following post, we are going deep on immutability using Java and the complexity of building those systems.

If you liked this post and are interested in hearing more about my journey as a Software Engineer, you can follow me on Twitter and travel together.

Advertisement

11 comments

  1. Great post, 2 small suggestions:

    1. There’s a typo: “Now, the Person objects are thread save.”, should be “Now, the Person objects are thread safe.”
    2. Fields in Person class should be declared final so no one can assign a new value to them, even the same Person class.

    Like

    • Thank you very much.

      1. Fixed
      2. Do not be anxious, this was immutability basics, I will go deep in the following posts.

      Like

  2. Hi, this method
    “`public void setBirthDate(String birthDate){
    this.birthDate = birthDate;
    }“`
    Should be
    “`public void setBirthDate(LocalDate birthDate){
    this.birthDate = birthDate;
    }“` 😉

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s