Libellés

lundi 27 juin 2011

Groovy et l'immutabilité

Depuis la version 1.8, Groovy permet de rendre des classes entièrement immutables, c'est à dire des classes qui ne peuvent pas changer d'état.

Ceci peut être pratique pour écrire du code thread safe.

Voici un exemple de classe immutable en Groovy.
PS : ne surtout pas oublier le import groovy.transform.Immutable, sinon c'est l'ancien groovy.lang.Immutable qui est utilisé (Cf : http://comments.gmane.org/gmane.comp.lang.groovy.user/55021)


import groovy.transform.Immutable

@Immutable
final class Punter {
String first
String last
Map params
}

@Immutable
final class PunterWrapper {
String name
Punter punter
}


def wrapper = new PunterWrapper(
name: 'hi',
punter: new Punter(
first: 'Foo',
last: 'Bar',
params: [k: 'value']
)
)


println wrapper

try{
wrapper.punter.params.toto = 3
}catch(Exception e){
println('Exception catched ')
}

try{
wrapper.punter.last = 'Tutu'
}catch(Exception e){
println('Exception catched ')
}

try{
wrapper.name = 'Toto'
}catch(Exception e){
println('Exception catched ')
}

PunterWrapper(name:hi, punter:Punter(first:Foo, last:Bar, params:[k:value]))
Exception catched
Exception catched
Exception catched




Mais écrire des classes immutables en Groovy peux s'avérer complexe à gérer.

Pour éviter récrire le constructeur complet de l'objet à chaque fois que l'on souhaite modifier une valeur, voici une solution que j'ai trouvé :


println new PunterWrapper(wrapper.properties + [
name: 'Titi',
punter: new Punter(wrapper.punter.properties + [
first: 'Mickael'
])
])​

PunterWrapper(name:Titi, punter:Punter(first:Mickael, last:Bar, params:[k:value]))



Un nouvel objet est créé à partir des attributs modifiés de l'ancien objet.



On peut également travailler avec les Collections de la même façon :

def list = [a: 1,b: 2,c: 3].asImmutable()
println list

try{
list​.d=4
}catch(Exception e){
println 'Exception catched'
}


def list2 = (list + [d:4]).asImmutable()
​println list2


def listMutable = list2 + [e:5]
listMutable.f = 6
println listMutable


[a:1, b:2, c:3]
Exception catched
[a:1, b:2, c:3, d:4]
[a:1, b:2, c:3, d:4, e:5, f:6]



Mais il ne faut pas oublier le asImmutable() à chaque modification de la collection.


Groovy nous donne donc quelques possibilités pour travailler dans un environnement immutable, mais ce n'est pas encore très pratique.

Scala est mieux sur ce point là.

Aucun commentaire:

Enregistrer un commentaire