Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why an immutable class is mutable in Groovy?

Reading the "The Well-Grounded Java Developer" book by Benjamin J. Evans and Martijn Verburg I've encountered the following example in Groovy:

class Character {
    private int strength
    private int wisdom
}

def pc = new Character(strength: 10, wisdom: 15)
pc.strength = 18
println "STR [" + pc.strength + "] WIS [" + pc.wisdom + "]"

The output of the snippet is the following:

STR [18] WIS [15]

Till now there is no questions. The code above have been slightly modified with the @Immutable annotation, as the book suggests:

import groovy.transform.*

@Immutable
class Character {
    private int strength
    private int wisdom
}

def pc = new Character(strength: 10, wisdom: 15)

pc.strength = 18

println "STR [" + pc.strength + "] WIS [" + pc.wisdom + "]"

The output of the last snippet is still the same:

STR [18] WIS [15]

The expected result is anything but not like the one above...

Why does an object of an immutable class seem to act like a mutable one? Does conception of immutability in Groovy permit modification to class fields?

like image 987
Pavel Avatar asked Jan 03 '23 21:01

Pavel


2 Answers

In order to fix the issue that you reported is simple which is removing access modifier to fields. That should fix the issue.

import groovy.transform.Immutable
@Immutable
class Character {
    int strength
    int wisdom
}

def pc = new Character(strength: 10, wisdom: 15)

pc.strength = 18

println "STR [" + pc.strength + "] WIS [" + pc.wisdom + "]"

Now, it will raise an exception, saying below :

groovy.lang.ReadOnlyPropertyException: Cannot set readonly property: strength for class: Character
at Character.setProperty(Script1.groovy)
at Script1.run(Script1.groovy:10)

If you want more details on why the behavior is different, please refer here

like image 162
Rao Avatar answered Jan 11 '23 14:01

Rao


This behaviour is expected when explicitly setting the fields to private. The docs for Immutable state:

You don't have to follow Groovy's normal property conventions, e.g. you can create an explicit private field and then you can write explicit get and set methods. Such an approach, isn't currently prohibited (to give you some wiggle room to get around these conventions) but any fields created in this way are deemed not to be part of the significant state of the object and aren't factored into the equals or hashCode methods.

like image 25
cfrick Avatar answered Jan 11 '23 13:01

cfrick