J'ai souvent vu les termes immutable
et const
utilisés de manière interchangeable. Cependant, d'après ma (petite) expérience, les deux diffèrent beaucoup dans le "contrat" qu'ils font dans le code:
Immutable fait le contrat que cet objet ne changera pas que ce soit (par exemple Python tuples, Java chaînes)).
Const fait le contrat que dans le cadre de cette variable il ne sera pas modifié (aucune promesse que ce soit sur ce que d'autres threads pourraient faire à l'objet pointé pendant cette période, par exemple le mot-clé C/C++).
Évidemment, les deux ne sont pas équivalents, sauf si le langage est monothread (PHP), ou a un système de typage linéaire ou unique (Clean, Mercury, ATS).
Premièrement, ma compréhension de ces deux concepts est-elle correcte?
Deuxièmement, s'il y a une différence, pourquoi sont-ils presque exclusivement utilisés de manière interchangeable?
Je vais parler du C++, où cette différence est la plus pertinente.
Comme vous le constatez correctement, immuable signifie qu'un objet ne peut pas changer du tout après sa création. Cette création peut bien sûr se produire au moment de l'exécution, c'est-à-dire qu'un objet const
n'est pas nécessairement une constante au moment de la compilation. En C++, un objet est immuable si (1) et (2) ou (3) sont respectés:
Il n'a pas de membres déclarés mutable
qui sont mutés par les fonctions membres const
Il est déclaré const
const
les fonctions membres n'utilisent pas const_cast
pour supprimer const
qualification afin de muter tous les membres
Cependant, vous pouvez également envisager des modificateurs d'accès: si une opération mute en interne une instance, mais n'a aucun effet sur l'état de l'instance observable via son interface publique, alors l'objet est "logiquement immuable".
C++ fournit donc les outils nécessaires pour créer des objets immuables, mais comme la plupart des éléments en C++, les outils ne sont que minimalement suffisants et nécessitent une diligence pour être réellement utilisés. L'état d'une instance n'est pas nécessairement limité aux variables membres de l'instance - parce que C++ ne fournit pas un moyen d'imposer la transparence référentielle, il peut également inclure un état global ou de classe.
const
a également une autre fonction en C++: qualifier les références et les pointeurs. Une référence const
peut faire référence à un objet nonconst
. Il est légal (mais pas généralement nécessaire ou conseillé) d'utiliser const_cast
pour muter un objet via une référence const
, si et seulement si cet objet est déclaré non_const
:
int i = 4; // Non-const object.
const int* p = &i; // const pointer.
*const_cast<int*>(p) = 5; // Legal.
Et bien sûr, c'est un comportement indéfini de muter un objet const
:
const int i = 4; // const object.
const int* p = &i; // const pointer.
*const_cast<int*>(p) = 5; // Illegal.
En parlant de Java où le mot-clé "final" représente "const", considérez:
final Person someone = new Person();
Cela signifie que someone
ne peut JAMAIS faire référence à un autre objet Person. Mais, vous pouvez toujours modifier les détails de la personne référée. Par exemple. someone.setMonthlySalary(10000);
Mais, si someone
était un objet "immuable", l'une des conditions suivantes serait vraie: (a) Vous n'auriez pas de méthode nommée setMonthlySalary
(b) L'appel à setMonthlySalary lèverait toujours une exception comme UnsupportedOperationException
Les objets immuables sont ceux qui ne changent pas d'état après leur création. Par exemple;
string prefix = "Pre";
string postfix = "Post";
string myComplexStr = prefix + postfix;
Dans cet exemple, l'objet myComplexStr est immuable mais pas constant car sa valeur est calculée. Et il est immuable car il s'agit d'une chaîne et a une propriété de longueur statique et ne peut pas changer.
Les objets const sont généralement utilisés pour identifier certaines constantes réelles dont les valeurs sont connues avant la compilation comme Pi, "USA", "StackOverflow.com", les numéros de port, etc.
De ce point de vue, Const est différent des objets immuables car leurs valeurs ne sont pas calculées par le programme.
Mais si vous parlez du mot clé "const" en C++, vous pouvez dire que "const" est utilisé pour créer des objets immuables.
Premièrement, ma compréhension de ces deux concepts est-elle correcte?
Oui, mais votre deuxième question montre que vous ne comprenez pas ces différences.
Deuxièmement, s'il y a une différence, pourquoi sont-ils presque exclusivement utilisés de manière interchangeable?
const
en C++ n'est utilisé que pour le niveau d'accès (cela signifie "en lecture seule"), pas pour l'immuabilité. Cela implique que l'accès lui-même est totalement séparé des données. Par exemple, vous pouvez manipuler certaines données puis les exposer via une référence const. L'accès est en lecture seule, mais les données elles-mêmes, car toutes les données sont modifiables.
const ne garantit que les limitations d'accès, tandis que l'immuabilité (comme dans D par exemple) n'implique vraiment aucun moyen de modifier les données à quelque stade que ce soit de la vie de l'objet.
Maintenant, vous pouvez simuler l'immuabilité en C++ en vous assurant qu'il n'est pas possible d'accéder à certaines données autrement que const et en vous assurant qu'elles sont initialisées puis ne plus être touchées. Mais ce n'est pas une garantie solide car des langues comme D vous donnent lorsque vous marquez vos données comme immuables. Le langage s'assure qu'il n'est pas possible du tout d'effectuer une opération de modification de ces données, tandis qu'en C++, vous êtes toujours potentiellement en mesure de modifier les données via la conversion de const et la mutabilité si vraiment nécessaire.
Au final, ce n'est pas du tout le même car il n'offre pas du tout les mêmes garanties.
En parlant de JavaScript, les mots clés const
et Object.freeze
const
s'applique à liaisons variables
. Il crée une liaison immuable, vous ne pouvez pas lui attribuer une nouvelle valeur.
Object.freeze
fonctionne sur les valeurs des objets. Cela fait un objet immuable. À savoir, vous ne pouvez pas modifier ses propriétés.
En C++, ce sont les mêmes. Bien que vous puissiez modifier un objet const
si vous avez son emplacement en mémoire et l'autorisation du système d'exploitation pour écrire dans cette mémoire.
En C, C++ et langages apparentés, il existe également une différence entre un objet étant const et votre référence ou pointeur vers l'objet étant une référence constante.
Si vous essayez de modifier un objet constant, vous obtenez un comportement indéfini. (Vous pouvez essayer pour modifier un objet constant, par exemple en prenant son adresse, en convertissant l'adresse en un pointeur non const, puis en utilisant ce pointeur non const pour modifier l'objet).
Le pointeur ou la référence constante, d'autre part, indique simplement au compilateur que vous ne pouvez pas utiliser ce pointeur ou cette référence pour modifier l'objet. Vous pouvez caster le pointeur ou la référence et essayer de modifier l'objet. Si l'objet lui-même était constant, de mauvaises choses se produiront. Si l'objet n'était pas réellement constant, il changera. Bien sûr, cela peut dérouter les utilisateurs de votre code et éventuellement provoquer des bugs.
En C, si vous utilisez un littéral de chaîne comme "Bonjour", les cinq caractères et les zéro octets de fin sont en fait constants, mais vous obtenez un pointeur non const. Très mauvaise idée d'utiliser ce pointeur non constant pour changer l'objet.
En C, vous pouvez avoir un pointeur "const restrict". Cela signifie que l'objet pointé est temporairement constant. Si l'objet est modifié par tout moyen alors que le pointeur "const restrict" est dans la portée, vous obtenez un comportement indéfini. C'est plus fort qu'un pointeur const qui vous empêche seulement de changer un objet via ce pointeur.