Objets immuables et collections immuables
L'un des points les plus fins du débat sur les objets mutables et immuables est la possibilité d'étendre le concept d'immuabilité aux collections. Un objet immuable est un objet qui représente souvent une seule structure logique de données (par exemple une chaîne immuable). Lorsque vous avez une référence à un objet immuable, le contenu de l'objet ne changera pas.
Une collection immuable est une collection qui ne change jamais.
Lorsque j'effectue une opération sur une collection mutable, je change la collection en place et toutes les entités qui ont des références à la collection verront le changement.
Lorsque j'effectue une opération sur une collection immuable, une référence est renvoyée à une nouvelle collection reflétant la modification. Toutes les entités qui ont des références à des versions précédentes de la collection ne verront pas la modification.
Les implémentations intelligentes n'ont pas nécessairement besoin de copier (cloner) la collection entière pour fournir cette immuabilité. L'exemple le plus simple est la pile implémentée sous forme de liste chaînée unique et les opérations push / pop. Vous pouvez réutiliser tous les nœuds de la collection précédente dans la nouvelle collection, en ajoutant un seul nœud pour le push et en ne clonant aucun nœud pour le pop. L'opération push_tail sur une seule liste chaînée, par contre, n'est pas si simple ou efficace.
Variables / références immuables vs mutables
Certains langages fonctionnels prennent le concept d'immuabilité aux références d'objets elles-mêmes, n'autorisant qu'une seule affectation de référence.
- Dans Erlang, cela est vrai pour toutes les "variables". Je ne peux attribuer des objets à une référence qu'une seule fois. Si je devais opérer sur une collection, je ne pourrais pas réaffecter la nouvelle collection à l'ancienne référence (nom de variable).
- Scala intègre également cela dans le langage avec toutes les références déclarées avec var ou val , vals n'étant qu'une affectation unique et promouvant un style fonctionnel, mais vars permettant une structure de programme plus semblable à C ou à Java.
- La déclaration var / val est requise, alors que de nombreux langages traditionnels utilisent des modificateurs optionnels tels que final en java et const en C.
Facilité de développement vs performances
Presque toujours, la raison d'utiliser un objet immuable est de promouvoir une programmation sans effets secondaires et un raisonnement simple sur le code (en particulier dans un environnement hautement concurrent / parallèle). Vous n'avez pas à vous soucier de la modification des données sous-jacentes par une autre entité si l'objet est immuable.
Le principal inconvénient est la performance. Voici un article sur un test simple que j'ai effectué en Java comparant des objets immuables et mutables dans un problème de jouet.
Les problèmes de performances sont sans objet dans de nombreuses applications, mais pas dans toutes, c'est pourquoi de nombreux packages numériques volumineux, tels que la classe Numpy Array en Python, permettent des mises à jour sur place de grands tableaux. Cela serait important pour les domaines d'application qui utilisent de grandes opérations matricielles et vectorielles. Ces gros problèmes de parallélisme de données et de calcul intensif atteignent une grande accélération en fonctionnant sur place.
string
est immuable, du moins en .NET, et je pense également dans de nombreux autres langages modernes.