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?
1 Answer 1
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.
-
You are right my example differs with the actual problem. if we call
i
state,Immutable
should returni+1
and the difference is performance; But if I call it logic, it is something thatMutable
does it internally butImmutable
doesn't care. Preferring immutable solution make me to do a lot of work outside of an object which was supposed to encapsulate that logic. You can regard theMutable
a counter or a timer, they are good objects, not?! (Just I doubt!)Ahmad– Ahmad04/14/2015 16:25:28Commented Apr 14, 2015 at 16:25 -
Or maybe you mean that the right way is instead of updating the state inside the object, I should always update the state and return it in an Immutable solution. That makes sense!!Ahmad– Ahmad04/14/2015 16:34:35Commented Apr 14, 2015 at 16:34
-
1
You should prefer an immutable solution
-- As part of a UI? UI's are naturally mutable... Is it your position that a textbox object be replaced with a new textbox object every time some property on the textbox changes?Robert Harvey– Robert Harvey04/14/2015 16:37:12Commented Apr 14, 2015 at 16:37 -
@RobertHarvey He asked a broad question, I gave him a broad answer. You can always compute the new state that the UI will present in a purely functional way (not necessarily as efficiently, and your language of choice may make this awkward.) For the particular problem Ahmad gave I don't see any difficulty. He's just sequentially transforming and presenting some state. Returning the new state makes the transformation more obvious, and has less chance of causing trouble if two references to the same
TextDrawer
ever exist. Anyways, I used "prefer" precisely because there are exceptions.Doval– Doval04/14/2015 16:52:27Commented Apr 14, 2015 at 16:52 -
2The goal of functional programming isn't to disallow mutability, it is to make mutability explicit (paraphrased quote). Likewise, functional program doesn't try to hide the steps involved in rendering a textbox - it tries to expose the steps so that the caller can have very fine grained control. In this question, the steps involve first computing the word bounding boxes from the string, checking that against the boundary, then compute the wrapping. A functional programming approach will expose those steps to the caller. Now you can see places where immutability can / cannot apply.rwong– rwong04/14/2015 17:34:17Commented Apr 14, 2015 at 17:34
Explore related questions
See similar questions with these tags.
TextDrawer
has settable properties, so in neither case isTextDrawer
immutable. Also, even ifTextDrawer
had no settable properties, still,RECT
is mutable, therefore any class containing aRECT
is also mutable. Perhaps you are missing something with respect to whatimmutable
means?RECT
is immutable for the sake of argument. However, you're right about being able to assign these properties causingTextDrawer
to not be immutable.The second approach is immutable but actually shifts the responsibility of updating the remaining part outside of the class.
I don't get this statement. With both options you have to make a second call toDrawTextInBox
to draw the remaining part. The only difference is whether the remaining part is kept internally or returned explicitly.DrawTextInBox
is not pure and calling it each time makes a different result.(Am I correct?) anyway it is something I don't like about an object, what is called?