Pourquoi les chaînes sont-elles immuables dans certaines langues?

9

String est une classe immuable en Java. Une classe immuable est simplement une classe dont les instances ne peuvent pas être modifiées. Pourquoi le langage de programmation Java choisit-il de rendre les objets de la classe String immuables?

Tupledev
la source
2
@PJTraill Cela ne semble pas du tout inévitable. Les littéraux de chaîne dans d'autres langages ne sont pas immuables en C, par exemple, et les objets d'autres classes en Java ne sont pas immuables.
David Richerby
2
Il s'agit d'une question sur la conception du langage de programmation. Cela me semble sujet.
David Richerby
2
@DavidRicherby, les littéraux de chaîne sont immuables en C (en termes de C90: si le programme tente de modifier un littéral de chaîne de l'une ou l'autre forme, le comportement n'est pas défini. Une version antérieure l'a accepté en raison du manque de const dans le langage, parfois ce que le programmeur attendait, mais je ne pense pas que cela ait jamais été supporté) Je pense que tout le monde a appris de l'erreur du début de FORTRAN qui a permis de changer les littéraux. Avoir des littéraux créant un nouvel objet mutable dont la valeur initiale est la même que le littéral d'autre part si ce n'est pas quelque chose de mauvais.
AProgrammer
1
@AProgrammer Plenty a été écrit sur les raisons pour lesquelles Java a été conçu tel qu'il était: je serais surpris s'il n'y avait rien d'autorité dans les décisions de conception autour de la classe String. Mais, même si les concepteurs de langage n'ont jamais dit pourquoi String est immuable, cela ne rend pas la question hors sujet ou même mauvaise: cela signifie simplement que, malheureusement, la seule bonne réponse est "Nous ne savons pas".
David Richerby
1
@DavidRicherby Mais il serait préférable que la question soit indépendante de la langue. Celui-ci peut être répondu en citant une déclaration d'un développeur Java; nous voulons des réponses qui expliquent les concepts.
Raphael

Réponses:

9

Ce problème est fortement lié à la notion de ce que signifie être une instance d'une classe. En termes strictement orientés objet, une classe a un invariant associé: un prédicat qui est toujours vrai à la sortie d'une méthode (publique) de la classe. Une telle notion est essentielle pour garantir que l'héritage est bien défini, par exemple (il fait partie du principe de substitution de Liskov ).

L'un des problèmes les plus pernicieux avec Java est qu'il est difficile d'empêcher le code client de casser les invariants de classe.

Par exemple, considérez la classe «ZipCode» suivante:

class ZipCode {
    private String zipCode;

    public ZipCode(String value){
        if(!isValidZipCode(value))
            throw new IllegalArgumentException();
        zipCode = value;
        assert(invariant());
    }

    public String get() { return zipCode; }

    public boolean invariant() {
        return isValidZipCode( zipCode );
    }
}

Si String n'était pas immuable, il serait possible pour un utilisateur de ZipCode d'appeler `` get '' et de changer les caractères à tout moment ultérieur, brisant ainsi l'invariant et détruisant l'intégrité conceptuelle offerte par l'encapsulation du concept ZipCode.

Étant donné que ce type d'intégrité est essentiel pour garantir la validité des grands systèmes, cette réponse à votre question supplie vraiment la plus large de:

"Pourquoi Java ne prend-il pas en charge un analogue de const C ++, ou au moins ne propose-t-il pas de versions immuables de plusieurs de ses classes de bibliothèque?"

NietzscheanAI
la source
7

Des choses comme les chaînes et les dates sont naturellement des valeurs. En termes C ++, nous nous attendons à ce qu'ils aient un constructeur de copie, un opérateur d'affectation et un opérateur d'égalité, mais nous ne nous attendons jamais à prendre leur adresse. Par conséquent, nous ne nous attendons pas à ce qu'ils soient alloués individuellement sur le tas. Les méthodes virtuelles n'ont aucun sens.

Les objets de domaine sont naturellement des références. Ceux C ++ n'ont pas de constructeur de copie, d'opérateur d'affectation ou d'opérateur d'égalité (ils ne sont égaux que s'ils sont identiques). Nous pouvons prendre leur adresse et nous nous attendons à ce qu'ils soient alloués en tas. Les méthodes sont généralement virtuelles.

Java n'a pas de classes de valeur, seulement des classes de référence. Les valeurs sont truquées avec des objets immuables. Cela est vrai pour les chaînes, mais pas, malheureusement, pour les dates. La mutabilité des dates Java a causé des problèmes fréquents et est désormais obsolète. Les valeurs mutables ne peuvent pas être utilisées comme base pour un hachage, par exemple.

La vignette
la source
Eh bien, les valeurs mutables peuvent être utilisées pour le hachage, mais il vaut mieux ne pas les muter par la suite si vous vous êtes appuyé sur le code de hachage!
gnasher729
6

Java a été conçu pour permettre l'exécution de sous-sections du code d'un programme dans des environnements soumis à des contraintes de sécurité. La manière dont cette exigence a été mise en œuvre a été de définir un "SecurityManager" sur un thread qui a accès aux paramètres de certaines opérations critiques (par exemple, l'ouverture d'un fichier) et a demandé si l'opération devait être autorisée ou non. Si Java Strings était mutable, un programme pourrait contourner ces restrictions en créant deux threads, l'un qui effectuait une opération de fichier ouvert qui serait autorisé tandis que l'autre modifiait la chaîne dans laquelle il stockait le nom de fichier en un qui ne serait pas autorisé. Il est alors possible que le responsable de la sécurité lise la chaîne d'origine, accepte l'opération, qui sera transmise au code d'ouverture de fichier qui précédera ensuite l'ouverture du deuxième fichier (non autorisé).

  • cordes immuables
  • effectuer une copie défensive de toute chaîne critique de sécurité avant de vérifier son acceptabilité.

Cette dernière possibilité rendrait toutes ces opérations plus lentes et aurait plus de chances que l'implémentation contienne des bogues, donc l'utilisation de chaînes immuables était la décision la plus judicieuse.

Plus généralement, les objets immuables sont utiles car ils permettent le partage sans avoir besoin de faire des copies défensives (ce qui peut être nécessaire même dans un code non critique pour la sécurité pour éviter les bugs lorsque les données source changent), donc même sans cette exigence, la décision serait toujours raisonnable.

Jules
la source
1
Je suis content que quelqu'un l'ait signalé, car James Gosling était parfaitement clair sur cette décision de conception. Java a été conçu pour que vous puissiez exécuter du code non fiable qui vous est envoyé sur un réseau (par exemple dans un navigateur Web ou un décodeur numérique). La principale raison de rendre les chaînes immuables était de permettre aux fournisseurs ou aux gestionnaires de sites (et aux implémenteurs de bibliothèques standard Java!) D'implémenter facilement leurs propres politiques de sécurité personnalisées. Les chaînes immuables ferment efficacement un vecteur d'attaque potentiel par conception.
Pseudonyme