Un point important qui n’a pas encore été mentionné est que le fait que l’état d’un objet soit mutable permette de rendre immuable l’ identité de l’objet qui encapsule cet état.
De nombreux programmes sont conçus pour modéliser des choses du monde réel qui sont intrinsèquement mutables. Supposons qu’à 00h51, une variable AllTrucks
contienne une référence à l’objet n ° 451, qui est la racine d’une structure de données qui indique quelle cargaison est contenue dans tous les camions d’une flotte à ce moment-là (12h51), et certaines variables. BobsTruck
peut être utilisé pour obtenir une référence à l'objet # 24601, à un objet indiquant quelle cargaison est contenue dans le camion de Bob à ce moment-là (12h51). À 12h52, certains camions (y compris ceux de Bob) sont chargés et déchargés, et les structures de données sont mises à jour de sorte à AllTrucks
contenir une référence à une structure de données indiquant que la cargaison est dans tous les camions à compter de 12h52.
Que devrait-il arriver BobsTruck
?
Si la propriété 'cargo' de chaque objet camion est immuable, l'objet # 24601 représentera à tout jamais l'état du camion de Bob à 00h51. Si BobsTruck
contient une référence directe à l'objet n ° 24601, à moins que le code mis à jour ne soit AllTrucks
également mis à jour BobsTruck
, il ne représentera plus l'état actuel du camion de Bob. Notez en outre que, sauf si BobsTruck
est stocké dans une forme d'objet mutable, le code AllTrucks
pouvant être mis à jour pourrait être mis à jour uniquement si le code était explicitement programmé pour le faire.
Si on veut pouvoir BobsTruck
observer l'état du camion de Bob tout en maintenant tous les objets immuables, on pourrait avoir BobsTruck
une fonction immuable qui, étant donné la valeur qui AllTrucks
a eu ou a eu à un moment donné, donnera l'état du camion de Bob à ce temps. On pourrait même lui demander d’assumer deux fonctions immuables - l’une comme celle ci-dessus, et l’autre acceptant une référence à un état de flotte et un nouvel état de camion, et renvoyant une référence à un nouvel état de flotte correspondait à l'ancien, sauf que le camion de Bob aurait le nouvel état.
Malheureusement, avoir à utiliser une telle fonction à chaque fois que l'on veut accéder à l'état du camion de Bob pourrait devenir assez ennuyeux et encombrant. Une autre approche serait de dire que l’objet n ° 24601 restera toujours et à jamais (tant que quelqu'un en fera référence) représente l’ état actuel du camion de Bob. Le code qui voudra accéder de manière répétée à l'état actuel du camion de Bob n'aura pas à exécuter une fonction fastidieuse à chaque fois - il pourrait simplement faire une fonction de recherche une fois pour découvrir que l'objet # 24601 est le camion de Bob, puis simplement accéder à cet objet à tout moment, il veut voir l'état actuel du camion de Bob.
Notez que l'approche fonctionnelle n'est pas sans avantages dans un environnement mono-thread, ou dans un environnement multi-thread où les threads ne feront qu'observer les données plutôt que de les modifier. Tout fil de l'observateur qui copie la référence de l'objet contenue dansAllTrucks
et examine ensuite les états des camions représentés ainsi verront l’état de tous les camions à partir du moment où ils ont saisi la référence. Chaque fois qu'un thread observateur veut voir de nouvelles données, il peut simplement saisir à nouveau la référence. D'autre part, avoir l'ensemble de l'état de la flotte représenté par un seul objet immuable exclurait la possibilité que deux threads mettent à jour simultanément des camions différents, car chaque thread, laissé à lui-même, produirait un nouvel objet "state de la flotte", qui comprend: le nouvel état de son camion et les anciens états de tous les autres. L’exactitude peut être assurée si chaque thread utilise CompareExchange
pour se mettre à jour AllTrucks
que s’il n’a pas changé et répond à un échec.CompareExchange
en régénérant son objet d'état et en renouvelant l'opération, mais si plusieurs threads tentent une opération d'écriture simultanée, les performances seront généralement moins bonnes que si toutes les écritures étaient effectuées sur un seul thread; plus les threads tentent de telles opérations simultanées, plus les performances seront mauvaises.
Si des objets de camion individuels sont modifiables mais ont une identité immuable , le scénario multithread devient plus clair. Un seul fil peut être autorisé à fonctionner à la fois sur un camion donné, mais les fils fonctionnant sur des camions différents peuvent le faire sans interférence. Bien qu’il existe des moyens d’émuler un tel comportement, même lorsqu’on utilise des objets immuables (par exemple, on pourrait définir les objets "AllTrucks" de manière à ce que le réglage de l’état d’un camion appartenant à XXX à SSS nécessite simplement de générer un objet qui dit "À partir de [Heure], l'état du camion appartenant à [XXX] est maintenant [SSS]; l'état de tout le reste est [Ancienne valeur de AllTrucks] ". La génération d'un tel objet serait assez rapide pour que, même en cas de conflit, unCompareExchange
la boucle ne prendrait pas longtemps. D'autre part, l'utilisation d'une telle structure de données augmenterait considérablement le temps requis pour trouver le camion d'une personne donnée. L'utilisation d'objets mutables d' identités immuables évite ce problème.