Les champs en lecture seule peuvent être calculés lors de l'exécution du programme (contrairement aux constantes, qui sont connues à l'avance), mais ne changent jamais après leur initialisation.
immuabilité faible vs forte
On parle parfois d'immuabilité de certains champs d'un objet. Cela signifie qu'il est impossible de modifier ces parties de l'état de l'objet, même si d'autres parties peuvent être modifiées ( immuabilité faible ). Si tous les champs sont immuables, l'objet est immuable. Si l'objet entier ne peut être étendu par une autre classe, il est dit fortement immuable . Ceci peut, par exemple, permettre d'imposer explicitement certaines invariances concernant la constance de certaines données de l'objet tout au long de sa durée de vie. Dans certains langages, cela se fait à l'aide d'un mot-clé (par exemple consten C++ , finalen Java ) qui désigne le champ comme immuable. D'autres langages fonctionnent à l'inverse : en OCaml , les champs d'un objet ou d'un enregistrement sont immuables par défaut et doivent être explicitement marqués mutablecomme tels.
Références à des objets
Dans la plupart des langages orientés objet , les objets peuvent être référencés par des références . Java , C++ , C# , VB.NET et de nombreux langages de script , tels que Perl , Python et Ruby , en sont des exemples . Dans ce cas, il est important de savoir si l'état d'un objet peut varier lorsque des objets sont partagés par référence.
Référencer ou copier des objets
S'il est établi qu'un objet est immuable, il est préférable d'en créer une référence plutôt que de le copier intégralement. Ceci permet d'économiser de la mémoire en évitant la duplication des données et les appels aux constructeurs et destructeurs ; cela peut également améliorer la vitesse d'exécution.
La technique de copie par référence est beaucoup plus difficile à mettre en œuvre pour les objets mutables, car toute modification apportée à une référence par un utilisateur est répercutée sur tous les autres utilisateurs. Si ce comportement n'est pas souhaité, il peut s'avérer complexe de les informer et d'obtenir leur réaction appropriée. Dans ce cas, la copie défensive de l'objet entier plutôt que de la référence constitue généralement une solution simple, mais coûteuse. Le modèle observateur offre une alternative pour gérer les modifications apportées aux objets mutables.
Copie sur écriture
La technique de copie à l'écriture (COW) combine les avantages des objets mutables et immuables et est prise en charge directement par la quasi-totalité du matériel moderne. Grâce à cette technique, lorsqu'un utilisateur demande au système de copier un objet, celui-ci crée simplement une nouvelle référence pointant toujours vers le même objet. Dès qu'un utilisateur tente de modifier l'objet via cette référence, le système en effectue une copie réelle, y applique la modification et met à jour la référence pour qu'elle pointe vers la nouvelle copie. Les autres utilisateurs ne sont pas affectés, car ils continuent de faire référence à l'objet original. Ainsi, avec la COW, tous les utilisateurs semblent disposer d'une version mutable de leurs objets, même si, lorsqu'ils ne les modifient pas, les avantages des objets immuables en termes d'économie d'espace et de rapidité sont préservés. La copie à l'écriture est courante dans les systèmes de mémoire virtuelle car elle permet d'économiser de l'espace mémoire tout en assurant une gestion correcte des actions des applications.
Stage
L'utilisation systématique de références plutôt que de copies d'objets identiques est appelée intérim . Si l'intérim est utilisé, deux objets sont considérés comme égaux si et seulement si leurs références, généralement représentées par des pointeurs ou des entiers, sont identiques. Certains langages implémentent cela automatiquement : par exemple, Python intérime automatiquement les chaînes de caractères courtes . Si l'algorithme d'intérim garantit cette intérim dans tous les cas possibles, la comparaison d'objets se réduit à la comparaison de leurs pointeurs, ce qui représente un gain de vitesse considérable dans la plupart des applications. (Même si l'algorithme n'est pas exhaustif, il existe toujours la possibilité d'une optimisation rapide lorsque les objets sont égaux et utilisent la même référence.) L'intérim est généralement utile uniquement pour les objets immuables.
Sécurité du fil
Les objets immuables sont utiles dans les applications multithread. Plusieurs threads peuvent manipuler des données représentées par des objets immuables sans craindre que ces données ne soient modifiées par d'autres threads. Les objets immuables sont donc considérés comme plus sûrs pour les threads que les objets mutables.
Violation de l'immuabilité
L'immuabilité n'implique pas que l'objet stocké en mémoire soit inaltérable. Il s'agit plutôt d'une construction de compilation indiquant ce qu'un programmeur peut faire via l'interface normale de l'objet, et non pas nécessairement ce qu'il peut absolument faire (par exemple, en contournant le système de types ou en violant la cohérence des constantes en C ou C++ ).
Détails spécifiques à la langue
En Python , Java et dans le .NET Framework , les chaînes de caractères sont des objets immuables. Java et le .NET Framework proposent des versions mutables de chaînes de caractères. En Java , il s'agit StringBufferde `string` et StringBuilder`string` (versions mutables de Java Python 3 propose une variante mutable de chaînes de caractères (octets), nommée `string` bytearray.
De plus, toutes les classes d'encapsulation primitives en Java sont immuables.
Des modèles similaires sont l' interface immuable et de programmation purement fonctionnels, il n'est pas possible de créer des objets mutables sans étendre le langage (par exemple via une bibliothèque de références mutables ou une interface de fonction étrangère ), donc tous les objets sont immuables.
Ada
En Ada , tout objet est déclaré soit variable (c'est-à-dire mutable ; généralement la valeur par défaut implicite), soit constant(c'est-à-dire immuable) via le constantmot-clé.
readonlyinstruction. En imposant l'immuabilité de tous les champs, le type devient un type immuable.ShoppingCart permettrait à l'utilisateur de créer des instances de la classe et de les utiliser ensuite comme const`immuables` ou `mutables`, selon ses besoins, en fournissant deux versions différentes de la items()méthode `set`. (Notez qu'en C++, il n'est pas nécessaire, et même impossible, de fournir un constructeur spécialisé pour constles instances.)const depuis l'intérieur d'une méthode.constint` et immutable`mutable`, pour les variables qui ne peuvent pas être modifiées. Contrairement à `int` en C++ const, `mutable` en Java finalet `mutable` en C# readonly, ils sont transitifs et s'appliquent récursivement à tout élément accessible par référence à une telle variable. La différence entre `int` constet immutable`mutable` réside dans leur objet : `int` constest une propriété de la variable ; il peut exister légalement des références mutables à la valeur référencée, c'est-à-dire que la valeur peut effectivement changer. En revanche, `mutable` immutableest une propriété de la valeur référencée : la valeur et tout élément transitivement accessible à partir d'elle ne peuvent pas être modifiés (sous peine de rompre le système de types et d'entraîner un comportement indéfini ). Toute référence à cette valeur doit être marquée `int` constou ` immutablemutable`. En résumé, pour tout type non qualifié T, ` const(T)int` est l'union disjointe de T`int` (mutable) et `mutable` immutable(T).Comme constles paramètres ne conservent pas la trace de leur valeur mutable, une construction similaire, inout`is`, sert en quelque sorte de variable pour l'information de mutabilité. Une fonction de type ` const(S) function(const(T))is` renvoie des valeurs typées pour les arguments mutables, constants et immuables. En revanche, une fonction de type ` is` renvoie `true` pour les arguments mutables, ` false` pour les valeurs `const` et `false` pour les valeurs ` const(S)immuable`.inout(S) function(inout(T))STconst(S)const(T)immutable(S)immutable(T)
La conversion de valeurs immuables en valeurs mutables entraîne un comportement indéfini lors de toute modification, même si la valeur d'origine provient d'une source mutable. La conversion de valeurs mutables en valeurs immuables est autorisée s'il ne subsiste aucune référence mutable. « Une expression peut être convertie de mutable (...) à immuable si elle est unique et si toutes les expressions auxquelles elle fait référence transitivement sont soit uniques, soit immuables. » Si le compilateur ne peut pas prouver l'unicité, la conversion peut être effectuée explicitement et il incombe au programmeur de s'assurer de l'absence de références mutables.
Ce type stringest un alias pour `string` immutable(char)[], c'est-à-dire une tranche de mémoire typée de caractères immuables. La création de sous-chaînes est peu coûteuse, car elle se limite à copier et modifier un pointeur et un champ de longueur, et sûre, car les données sous-jacentes ne peuvent être modifiées. Les objets de ce type const(char)[]peuvent faire référence à des chaînes de caractères, mais aussi à des tampons mutables.
Effectuer une copie superficielle d'une constante ou d'une valeur immuable supprime la couche d'immuabilité externe : la copie d'une chaîne immuable immutable(char[])renvoie une chaîne immutable(char)[]. Le pointeur immuable et la longueur sont copiés, et les copies sont mutables. Les données référencées n'ont pas été copiées et conservent leur qualificateur, dans l'exemple immutable. Ce qualificateur peut être supprimé en effectuant une copie plus profonde, par exemple à l'aide de la dupfonction `delete`.
Java
Un exemple classique d'objet immuable est une instance de la Stringclasse Java
Cette méthode toLowerCase()ne modifie pas les données « ABC » qu'elle scontient. Elle crée un nouvel objet String auquel elle attribue les données « abc » lors de sa construction. La méthode renvoie une référence à cet objet String toLowerCase(). Pour que la chaîne scontienne les données « abc », une autre approche est nécessaire :
Les variables de type primitif ( int, long, short, etc.) peuvent être réassignées après leur définition. Ceci peut être évité en utilisant final.
L'utilisation d'un état immuable est devenue une tendance croissante en JavaScript depuis l'introduction de React , qui privilégie les modèles de gestion d'état de type Flux tels que Redux .
Perl
En Perl , on peut créer une classe immuable avec la bibliothèque Moo en déclarant simplement tous les attributs en lecture seule :
package Immutable ; use Moo ;a valeur => ( est => 'ro' , # lecture seule par défaut => 'data' , # peut être surchargé en fournissant au constructeur # une valeur : Immutable->new(valeur => 'autre chose'); );1 ;
La création d'une classe immuable nécessitait auparavant deux étapes : premièrement, la création d'accesseurs (automatiquement ou manuellement) empêchant la modification des attributs de l'objet, et deuxièmement, la prévention de la modification directe des données d'instance des instances de cette classe (celles-ci étaient généralement stockées dans une référence de hachage et pouvaient être verrouillées avec la fonction lock_hash de Hash::Util) :
package Immutable ; use strict ; use warnings ; use base qw(Class::Accessor) ; # créer des accesseurs en lecture seule __PACKAGE__ -> mk_ro_accessors ( qw(value) ); use Hash::Util 'lock_hash' ;sub new { my $class = shift ; return $class if ref ( $class ); die "Les arguments de new doivent être des paires clé => valeur " unless ( @_ % 2 == 0 ); my %defaults = ( value => 'data' , ); my $obj = { %defaults , @_ , }; bless $obj , $class ; # empêcher la modification des données de l'objet lock_hash %$obj ; } 1 ;
Ou encore, avec un accesseur écrit manuellement :
package Immutable ; use strict ; use warnings ; use Hash::Util 'lock_hash' ;sub new { my $class = shift ; return $class if ref ( $class ); die "Les arguments de new doivent être des paires clé => valeur " unless ( @_ % 2 == 0 ); my %defaults = ( value => 'data' , ); my $obj = { %defaults , @_ , }; bless $obj , $class ; # empêcher la modification des données de l'objet lock_hash %$obj ; }# sous - objet d'accès en lecture seule { my $self = shift ; if ( my $new_value = shift ) { # tentative de définition d'une nouvelle valeur die "Cet objet ne peut pas être modifié " ; } else { return $self -> { value } } } 1 ;
PHP
En PHP, les propriétés sont en lecture seule depuis la version 8.1 et les classes en lecture seule depuis la version 8.2.
classe BlogData en lecture seule { public string $title ;Statut public $statut ;public function __construct ( string $title , Status $status ) { $this -> title = $title ; $this -> status = $status ; } }
Python
En Python , certains types intégrés (nombres, booléens, chaînes de caractères, tuples, ensembles figés) sont immuables, mais les classes personnalisées sont généralement mutables. Pour simuler l'immuabilité d'une classe, on peut redéfinir la gestion des attributs (définition et suppression) afin de lever des exceptions.
from typing import Any , NoReturnclasse ImmutablePoint : Une classe immuable avec deux attributs 'x' et 'y'."""__slots__ : liste [ str ] = [ "x" , "y" ]def __setattr__ ( self , * args : tuple [ Any , ... ]) -> NoReturn : raise TypeError ( "Impossible de modifier une instance immuable." )__delattr__ : Callable [[ Tuple [ Any , ... ]], NoReturn ] = __setattr__def __init__ ( self , x : int , y : int ) -> None : # On ne peut plus utiliser self.value = value pour stocker les données de l'instance # il faut donc appeler explicitement la superclasse super () .__ setattr__ ( "x" , x ) super () .__ setattr__ ( "y" , y )
Les fonctions d'assistance de la bibliothèque standard `int` collections.namedtupleet typing.NamedTuple`int`, disponibles à partir de Python 3.6, permettent de créer des classes immuables simples. L'exemple suivant est globalement équivalent au précédent, avec en plus quelques fonctionnalités similaires aux tuples :
Introduites dans Python 3.7, dataclassesces fonctionnalités permettent aux développeurs d'émuler l'immuabilité avec des instances figées . Si une classe de données figée est créée, dataclasseselle sera surchargée __setattr__()et __delattr__()une exception sera levée FrozenInstanceErrorlors de son invocation.
mcons, ` cons` mcar, set-mcar!etc. De plus, de nombreux types immuables sont pris en charge, comme les chaînes de caractères et les vecteurs immuables, et sont largement utilisés. Les nouvelles structures sont immuables par défaut, sauf si un champ est explicitement déclaré mutable, ou si la structure entière l'est.mutmot-clé `mutable`.Les objets constants en Rust sont toujours immuables.
val`value` pour les entités immuables et var`variable` pour les entités mutables. Notez que même si une liaison immuable ne peut pas être réassignée, elle peut néanmoins faire référence à un objet mutable et il est toujours possible d'appeler des méthodes de mutation sur cet objet : la liaison est immuable, mais l' objet sous-jacent peut être mutable.Par exemple, l'extrait de code suivant :
Plus d articles de Worldlex Wiki
Revenez a l index pour explorer davantage de pages sur l histoire, la science, la culture, la geographie et la societe en francais.
Explorer l index