Différence entre immuable et const

28

J'ai souvent vu les termes immutableet constutilisé 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 des tuples Python, des chaînes Java).

Const fait le contrat que dans la portée de cette variable, elle ne sera pas modifiée (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?

K.Steff
la source
1
constn'existe pas dans toutes les langues, et la mutabilité et l'immuabilité n'existent pas dans toutes les langues, donc rendre ce langage agonistique n'est pas applicable. Il est spécifique au langage uniquement lorsque ces concepts s'appliquent.
2
Lecture connexe et recommandée: Types d'immuabilité (quelques exemples C #, mais largement indépendants du langage). Quelqu'un donne à Eric Lippert une médaille.

Réponses:

14

Je vais parler de 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 constobjet 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:

  1. Il n'a pas de membres déclarés mutablequi sont mutés par constles fonctions membres

  2. Il est déclaré const

  3. constles fonctions membres n'utilisent pas const_castpour supprimer la constqualification afin de muter des 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 très peu 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 - car C ++ ne fournit pas un moyen d'imposer la transparence référentielle, il peut également inclure un état global ou de classe.

consta également une autre fonction en C ++: qualifier les références et les pointeurs. Une constréférence peut faire référence à un non- constobjet. Il est légal (mais pas généralement nécessaire ou conseillé) d'utiliser const_castpour muter un objet via une constréférence, 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 constobjet:

const int  i = 4;         // const object.
const int* p = &i;        // const pointer.

*const_cast<int*>(p) = 5; // Illegal.
Jon Purdy
la source
19

En parlant de Java où le mot-clé "final" représente "const", considérons:

final Person someone = new Person();

Cela signifie que vous someonene pouvez JAMAIS faire référence à un autre objet Personne. Mais, vous pouvez toujours modifier les détails de la personne référée. Par exemplesomeone.setMonthlySalary(10000);

Mais, s'il someones'agissait d'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 telle queUnsupportedOperationException

rationalrevolt
la source
10

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.

Mert Akcakaya
la source
1
const en C ++ ne crée pas d'objets immuables, c'est seulement un niveau d'accès.
Klaim
Pouvez-vous expliquer comment "const double pi = 3.14" n'est pas immuable?
Mert Akcakaya
Ça dépend où ça se trouve. Disons que je fais: "double * p_pi = const_cast <double *> (& pi); * p_pi = 42;" par exemple. Ensuite, si pi est dans l'espace global ou l'espace de noms, j'obtiens un défaut de segmentation, mais c'est, je crois, un comportement non défini, pas une erreur spécifique. Si pi est membre d'un objet disponible au moment de l'exécution, qui n'est pas statique, j'obtiens pi == 42. Vous voyez, même l'utilisation de mutable est disponible car const en C ++ concerne le niveau d'accès, sémantique, pas l'immuabilité des données, qui est presque impossible à réaliser en C ++. Vous ne pouvez que le "simuler". const n'est pas immuable.
Klaim
1
@Klaim Mutant un constsemblable qui est un comportement indéfini, peu importe où il est alloué, IIRC. Et un comportement indéfini est pire que toute erreur spécifique garantie. Cela signifie que vous n'utilisez plus C ++ - C ++ ne fournit aucun moyen de modifier une constvaleur (sauf les mutablemembres bien sûr, mais ce n'est pas votre point), donc en ce qui concerne C ++, vous ne pouvez pas le faire. Ce que les implémentations spécifiques autorisent est une tout autre affaire (et je parie que si vous compilez avec des optimisations, le coup que vous avez tiré n'affectera pas les expressions ultérieures picar il a été remplacé).
"const en C ++ ne crée pas d'objets immuables" est toujours faux car il crée toujours des constantes globales comme vous l'avez indiqué dans votre propre réponse. Le mot-clé est bien sûr sémantique à un certain niveau, sinon vous pouvez toujours modifier manuellement la tension d'une cellule mémoire et changer la valeur d'un objet immuable si vous êtes si désireux d'utiliser même des comportements non définis.
Mert Akcakaya
8

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?

consten 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, alors 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 pareil car il n'offre pas du tout les mêmes garanties.

Klaim
la source
3

En parlant de JavaScript, les mots clés constetObject.freeze

consts'applique aux liaisonsvariables . Il crée une liaison immuable, vous ne pouvez pas lui attribuer une nouvelle valeur.

Object.freezefonctionne sur les valeurs des objets. Cela rend un objet immuable . À savoir, vous ne pouvez pas modifier ses propriétés.

zangw
la source
0

En C ++, ce sont les mêmes. Bien que vous puissiez modifier un constobjet si vous avez son emplacement en mémoire et l'autorisation du système d'exploitation pour écrire dans cette mémoire.

Martin Beckett
la source
1
En fait, c'est un argument contre qu'ils soient les mêmes: C ++ n'a tout simplement aucun support de mot-clé ou de langage immuable. Et aussi, je suppose que le programmeur utilise le langage d'une manière sensée: sinon, const, lui aussi, n'a absolument aucune valeur.
K.Steff
1
@ K.Steff - peut-être mieux de dire qu'il n'y a pas d'immuabilité supplémentaire en C ++ autre que celle fournie par const
Martin Beckett
Absolument précis :)
K.Steff
En C ++, ils ne sont pas du tout les mêmes. const est un niveau d'accès "en lecture seule", cela ne signifie pas que les données sont immuables. Vous pouvez le contourner en C ++, la plupart du temps.
Klaim
0

En C, C ++ et les 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 de 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.

gnasher729
la source