Question

I know immutable objects are preferred to mutable objects for reasoning and maintenance. But in occasions making a class immutable have some costs, let me explain it with a simple example:

class Mutable  
{
    private int i;
    public Mutable(int _i) { i = _i}
    public void Print() // impure function
    {
         print(i);
         i++;   // logic inside
    }
}

... caller

Immutable m = new Mutable(1);
while (true)
{        
    m.Print();
}

I call it mutable because its internal state changes and Print varies on each call.

Versus.

class Immutable  
{
    private int i;
    public Mutable(int _i) { i = _i}
    public int Print() // pure function
    {
         print(i);
         return i;  // returns its state  
    }
}

... caller
int i =1;
while (true)
{
    Immutable im = new Immutable(i);
    i = im.Print(); // get the previous obeject's state
    i++; // logic outside
}

Preferring immutable solution make me to do a lot of work outside of an object which was supposed to encapsulate that logic.


My actual problem (you may skip the example below)

I have a class which draws a text in a box:

class TextDrawer
{
   private string text;
   private Rectangle box;
   public TextDrawer(_text, _box) {...}
   public void DrawTextInBox()
   {
   }
}

It is probable that the Text overflows from the box and part of it wasn't written. I should know the remaining unwritten part to draw it in a new box.(in fact I take an snapshot of the old box as a video frame and need to make a new frame for the remaining text to make a video of the text)

Now I have two options:

1- Make the TextDrawer mutable (its internal state is mutable) and DrawTextInBox a non-pure function and on each call it draws the remaining part of text in the box.

class TextDrawer
{

   private string text;
   private Rectangle box;
   private string remaining;   

   public TextDrawer(_text, _box)
   {
      remaining = text = _text;
      box = _box;
   }    
   public void DrawTextInBox()
   {
      draw as you can from remaining
      update remaining part;
   }
}

2- Keep the TextDrawer immutable and DrawTextInBox a pure function which returns the remaining part, then the caller should keep track of the remaining and pass it again to the TextDrawer or instantiate a new TextDrawer by the remaining text until there is nothing to write.

class TextDrawer
{
   private string text;
   private Rectangle box;
   public TextDrawer(_text, _box) { ... }
   public string DrawTextInBox()
   {
       draw as you can from text;
       return remaining part;
   }
}

The second approach is immutable but actually shifts the responsibility of tracking the remaining part outside of the class. The first approach is mutable, but it encapsulates the logic and just need a call to DrawTextInBox to draw the remaining part.


Question: The logic of the above examples was simple but this logic could be more complex, then I don't know whether to extract this logic from a class in order to make it immutable or let it be mutable and have the logic inside?

Was it helpful?

Solution

In your example:

int i =1;
while (true)
{
    Immutable im = new Immutable(i);
    i = im.Print(); // get the previous obeject's state
    i++; // logic outside
}

Immutable should return the new state that the mutable solution would've stored, i.e. i + 1. You already have the old state. Returning the old state and forcing the caller to update the state himself is pointless. You did this correctly in your real problem, where you return the remaining part of the string instead of the original string.

You should prefer an immutable solution unless you have good reasons otherwise. A good reason may be that the immutable solution is too slow, but first you have to clearly define what's "fast enough" and profile the application to show that the bottleneck is your immutable class and that the mutable alternative will solve the problem.

Licensed under: CC-BY-SA with attribution
scroll top