Cet article est uneébauche concernant l’informatique.
Unobjet immuable, en programmationorientée objet etfonctionnelle, est unobjet dont l'état ne peut pas être modifié après sa création. Ce concept est à contraster avec celui d'objet variable.
Avant l'apparition de laprogrammation orientée objet, les variables d'exécution dont le contenu n'était pas destiné à changer en cours d'exécution (par exemple, le facteur de conversion permettant de transformer deslivres enkilogrammes, ou encore la valeur depi avec plusieurs décimales) étaient connues sous le nom deconstantes, pour les différencier de celles qui pouvaient être modifiées.
Dans la plupart des langages orientés objet, les objets sont manipulés par desréférences. C'est le cas, par exemple, deJava, des objets de typeclass
deC# et deSwift (contrairement aux objets de typestruct
), dePython, deJavaScript et deRuby. Dans ce cas, le fait que l'état d'un objet partagé par référence puisse ou non être modifié est important.
Lorsqu'un objet est réputé immuable, on peut en obtenir une copie en dupliquant simplement sa référence, au lieu de copier l'objet entier. Comme une référence (qui n'occupe typiquement en mémoire que la taille d'unpointeur) est habituellement bien moins volumineuse que l'objet lui-même, cette technique permet à la fois d'économiser de la mémoire et d'améliorer la vitesse d'exécution.
La technique de copie des références est bien plus complexe à utiliser pour les objets variables, parce que si un élément quelconque utilisant la référence à un objet variable modifie ce dernier, la modification deviendra visible pour tous les autres éléments utilisateurs de la référence. Au cas où ce ne serait pas l'effet souhaité, il peut s'avérer difficile de faire répondre correctement les autres utilisateurs. Dans une telle situation, la copie préventive de l'objet dans son ensemble constitue une solution fréquemment utilisée, mais coûteuse. Lepatron de conception observateur représente une solution alternative pour la gestion des modifications des objets variables.
Les objets immuables peuvent être utilisés dans des applicationsmulti-threads. Plusieurs threads peuvent utiliser des données implémentées en tant qu'objets immuables, sans se préoccuper d'une éventuelle modification par un thread concurrent. C'est pourquoi les objets immuables sont considérés comme plus sûrs dans un contexte multi-threads que les objets variables.
La technique qui consiste à toujours utiliser des références au lieu de copies d'objets identiques immuables, en ne stockant qu'une seule fois en mémoire leur valeur, porte en anglais le nom d'« interning ». Dans ce cadre, deux objets sont considérés comme égaux si et seulement si leurs références, typiquement représentées par des entiers, sont égales. Certains langages gèrent cette technique automatiquement : par exemple,Python gère automatiquement de cette manière les chaînes courtes. Si l'algorithme qui implémente l'interning garantit de l'effectuer chaque fois que c'est possible, alors la comparaison d'égalité entre deux objets se réduit à la comparaison de leurs pointeurs, ce qui représente un gain en rapidité substantiel dans la plupart des applications. L'interning ne présente généralement d'intérêt que pour les objets immuables.
Il peut arriver que seuls certains champs d'un objet soient immuables : l'objet lui-même est immuable seulement si tous ses champs sont immuables. Ceci peut permettre par exemple de contraindre certaines données d'un objet à rester invariables tout au long de la vie de l'objet. Dans certains langages, ceci se réalise au moyen d'un mot-clé (commeconst
enC++, oufinal
enJava). Dans d'autres langages, c'est l'inverse : enOCaml, les champs d'un objet sont immuablespar défaut, et doivent être marqués explicitement comme variables le cas échéant.
L'immuabilité n'implique pas que l'objet, tel qu'il est stocké en mémoire, ne puisse être réécrit. Il s'agit plutôt d'une directive de compilation indiquant ce qu'un programmeur a le droit de faire via l'interface normale de l'objet, et non ce qu'il est possible de faire dans l'absolu (par exemple en contournant le système de typage ou en violant les règles de gestion desconst
en C ou en C++).
Voici un exemple d'objet immuable en C# :
classPosition2D{privatereadonlydouble_x;privatereadonlydouble_y;publicdoubleX{get{return_x;}}publicdoubleY{get{return_y;}}publicPosition2D(doublex,doubley){_x=x;_y=y;}}
Un exemple classique d'objet immuable en Java est l'instanciation de la classeString
:
Strings="ABC";s.toLowerCase();
La méthodetoLowerCase()
ne modifie pas la valeur "ABC" contenue dans la chaînes
. Au lieu de cela, un nouvel objet String est instancié, et la valeur "abc" lui est attribuée lors de sa construction. La méthodetoLowerCase()
retourne une référence à cet objet String. Si l'on souhaite que la chaînes
contienne la valeur "abc", il faut utiliser une approche différente :
s=s.toLowerCase();
Dans ce cas, la chaînes
référence un nouvel objet String qui contient "abc". Rien dans la déclaration d'un objet de classe String ne le contraint à être immuable : c'est plutôt qu'aucune des méthodes associées à la classe String n'affecte jamais la valeur d'un tel objet, ce qui le rend de fait immuable.
Voici à présent un exemple d'objet Java, qui en fonction des différentes définitions de l'immuabilité peut être considéré soit comme variable, soit comme immuable. Si l'on considère que l'immuabilité des objets référencés découle de l'immuabilité de l'objet qui porte la référence (une sorte d'« immuabilité profonde »), alors l'objet ci-dessous est variable, car il comporte une référence à un objet List, qui peut être variable. Si, en revanche, on ne considère que la valeur de la référence elle-même, et non l'objet vers lequel elle pointe (une sorte d'« immuabilité de surface »), alors cet objet est immuable, car il ne fournit aucune interface (méthode ou champ non privé) permettant de modifier de l'extérieur la valeur de l'un quelconque de ses champs (y compris la valeur de la référence à l'objet List).
classPanier{privatefinalListarticles;publicPanier(Listarticles){this.articles=articles;}publicListgetArticles(){returnarticles;}publicinttotal(){/* retourne le prix total */}}
Si l'on souhaite garantir que l'objet List est également immuable, alors la modification suivante résout partiellement le problème. Dans la classePanierImmuable
, la liste n'est pas variable : il est impossible d'y ajouter ou d'en retirer des articles. Toutefois, il n'est pas garanti que les articles soient eux aussi immuables. Une solution consiste à inclure chaque article de la liste dans unpatron de conception décorateur conteneur pour le rendre également immuable. Une autre solution consisterait à ne laisser aucune référence aux articles de l'objet List s'échapper de la classePanierImmuable
en utilisant l'instructionreturn new ArrayList(articles);
dans la méthodegetArticles()
.
classPanierImmuable{privatefinalListarticles;publicPanierImmuable(Listarticles){this.articles=Collections.unmodifiableList(newArrayList(articles));}publicListgetArticles(){returnarticles;}publicinttotal(){/* retourne le prix total */}}
Les instances des classes enveloppes (types objets enveloppant les types primitifs)Integer
,Long
,Short
,Double
,Float
,Character
,Byte
,Boolean
sont également immuables.
Les classes immuables peuvent être implémentées en suivant quelques recommandations simples[1].
En langage Python, les typesbool
,tuple
,str
,bytes
,frozenset
,range
sont immuables, ainsi que les types numériquesint
,float
etcomplex
. La liste n'est pas exhaustive[2].
Les objetstuple
sont des listes immuables d'objets hétérogènes en Python. On peut voir le typetuple
comme le pendant immuable delist
, etfrozenset
comme le pendant immuable deset
. Contrairement à ce qu'on observe par exemple en langage Ruby, les chaînes de caractères (str
) sont immuables. Les chaînes d'octets (bytes
) également, mais il existe un typebytearray
variable.
L'objet symbole est immuable en Ruby, il est noté :
:symbole
Par défaut, les variables et les objets sont immuables ou non mutables. Le symbolemut
permet de les rendre mutables.