6
votes

Avantages et inconvénients de cordes immuables

Certaines langues (C # ou Java) ont des chaînes immuables tandis que d'autres (par exemple, ruby) ont mutable. Quelles sont les raisons de ces choix desgin?


4 commentaires

Voici quelque chose de similaire: Stackoverflow.com/questions/3407403/...


@Science_Fiction La meilleure réponse à cette question concerne l'immuabilité en général. Mais pourquoi les chaînes? Je pense que cela a quelque chose à voir avec le collecteur des ordures mark-balayage.


Stackoverflow.com/Questtions/2608493/...


Voir aussi quand-d-python-allouer-allouer-nouvelle-mémoire- Strings identiques sur SO: IMHO Aucune réponse claire.


4 Réponses :


2
votes

au moins dans le cas de Java, une partie de la raison de la création de chaînes immuables était la sécurité et la sécurité thread-sécurité. Java place une prime sur la sécurité de l'exécution (il a été conçu à l'origine pour autoriser les boîtes de pointe et les navigateurs Web pour télécharger et exécuter du contenu à distance sans compromettre le système hôte). Pour aider à augmenter la sécurité, les chaînes sont immuables et ne peuvent être sous-classées. Cela signifie que le temps d'exécution Java peut transmettre et recevoir des chaînes de l'utilisateur tout en garantissant que la valeur de la chaîne restera constante (c'est-à-dire qu'un attaquant ne peut pas sous-classer la chaîne, transmettre ce qui ressemble à une chaîne valide dans une fonction, mais Changez ensuite la valeur ultérieurement pour accéder aux mauvaises données ou utiliser plusieurs threads multiples de sorte qu'une chaîne a l'air correcte à un moment donné, mais est ensuite mutée ultérieurement).

En outre, l'immuabilité comporte des avantages d'efficacité dans les systèmes multithreads, car aucun verrouillage ne doit être effectué sur la chaîne. Il permet également d'implémenter facilement des opérations de sous-chaîne, car de nombreuses chaînes peuvent partager le même réseau sous-jacent de caractères, bien que différents points de début et de fin.


0 commentaires

1
votes

Si vous y réfléchissez, tous les types de données fondamentaux sont immuables. Vous ne changez pas d'entier 10 en 11, vous remplacez 10 avec 11. Faire des cordes fondamentales, et immuables, permet une mise en commun et d'autres optimisations qui ne seraient pas possibles autrement.


3 commentaires

Et ce qui fait un type de données fondamental?


Un qui est intégré dans la langue (plutôt que d'ajout d'une bibliothèque ou d'une extension)


Dans certaines langues, le caractère est le type fondamental. Une chaîne est juste un tableau de caractères.



1
votes

Quant aux inconvénients, les chaînes immuables nécessitent des structures de données complémentaires mutables (c'est-à-dire des tampons à cordes) pour permettre des opérations économiques ajoutées, de réorganisation et d'autres opérations similaires.

Ces opérations effectuées sur des structures immuables nécessiteraient des quantités déraisonnables de ressources.

programmation à Lua a un explication brillante sur la question.


Pour réfléchir davantage, certaines langues (telles que les LISP communes) ont des fonctions non destructives et destructrices, d'autres - des listes immuables et mutables (Python).

Pour quote Un livre sur le LISP commun :

Si l'affectation est si lourde avec péril, pourquoi ne pas l'omettre de la Langue? Il y a deux raisons: expressivité et efficacité. L'affectation est le moyen le plus clair de modifier les données partagées. Et l'affectation est plus efficace que la liaison. La liaison crée un nouvel emplacement de stockage, qui alloue stockage, qui consomme de la mémoire supplémentaire (si le la liaison ne dépasse jamais de portée) ou taxes le collecteur des ordures (si La liaison finit par sortir de la portée).


Cependant, comme un contre-exemple, de nombreux interprètes JavaScript (qui ont des chaînes immuables), traitent des chaînes comme des tableaux mutables sur le niveau de mise en œuvre.

Dans la même veine, Clojure a des transitoires , qui ressemblent à des fonctions pures élégantes sur des structures de données immuables, mais à l'intérieur Utiliser l'état mutable pour une efficacité.


0 commentaires

5
votes

Une des raisons pour lesquelles des chaînes immuables sont bonnes est de faciliter la prise en charge d'unicode. Unicode moderne ne peut plus s'adapter efficacement à une cellule de données de taille fixe, qui tue la correspondance individuelle entre l'indice de chaîne et l'adresse de mémoire qui donne des cordes mutables leur avantage.


Dans le passé, la plupart des applications occidentales utilisaient des caractères monopy-octet (divers codages à base d'ASCII, ou EBCDIC ...), de sorte que vous pourriez généralement les gérer efficacement en traitant des cordes en tant que tampons d'octets (que dans les applications C traditionnelles).

Quand Unicode était assez nouveau, il n'y avait plus d'exigence pour quoi que ce soit en dehors des 16 premiers bits, Java a donc utilisé des caractères à double octet pour son chaîne S (et Stringbuffer s). Cela a utilisé deux fois la mémoire et ignoré tous les problèmes pouvant survenir des extensions Unicode au-delà de 16 bits, mais c'était pratique à l'époque.

Maintenant, Unicode n'est pas aussi nouveau, et tandis que les personnages les plus utilisés correspondent toujours à 16 bits, vous ne pouvez pas vraiment vous échapper avec prétendre que le plan de base multilingue est tout ce qui existe. Si vous souhaitez affirmer honnêtement une assistance Unicode, vous avez besoin de caractères de longueur variable ou même de cellules de caractère (32 bits?).

Avec des caractères de longueur variable, vous ne pouvez plus indexer une chaîne de longueur arbitraire dans O (1) - à l'échec de l'heure, vous devez compter depuis le début pour déterminer ce que le caractère de N'th. Cela tue également l'avantage principal des tampons de cordes mutables: la possibilité de modifier de manière transparente des substrings en place.

Heureusement, la plupart des manipulations de chaîne n'ont pas besoin de cette capacité de modification en place. Lexing, analyse et recherche Tout procéder sur une base séquentielle, itérative, du début à la fin. La recherche générale-and-remplacer n'a jamais été mise en place pour commencer, car la chaîne de remplacement ne doit pas nécessairement avoir la même longueur que l'original.


Concaténation Un nombre important de sous-chaînes n'a pas réellement besoin de modifier en place pour être efficace, non plus. Vous devez faire plus attention à ce sujet, car (comme d'autres l'ont souligné) une boucle de concaténation naïve peut facilement être O (n ^ 2) en allouant une nouvelle chaîne pour chacune des n-strings partielles ...

Un moyen d'éviter la concaténation naïfe est de fournir un Stringbuffer mutable Concatbuffer objet conçu pour faire une concaténation efficace. Une autre manière serait d'inclure un constructeur de string immuable qui prend un itérateur en une séquence de chaînes pour être (efficacement) concaténée.

Mais, plus généralement, il est possible d'écrire une bibliothèque de chaînes immuables concaténant efficacement par référence. Ce type de chaîne est souvent appelé " corde " ou "cordon" à suggérer qu'il s'agit d'au moins un peu plus de poids lourd que les chaînes de base qu'il est composée, mais à des fins de concaténation, il est beaucoup plus efficace, car il n'a pas besoin de recopier les données du tout!

Le lien Wikipedia ci-dessus indique que les données de données "de la corde" sont O (log n) de concaténer, mais le papier séminal " structures de données purement fonctionnelles " de Okasaki montre comment faire une concaténation dans O (1) heure.


2 commentaires

Juste quelques choses que je ne suis pas d'accord, je pense que vous avez touché tous les mauvais points. Tout d'abord, Unicode est une cartographie des points de code aux caractères et aux glyphes. Le schéma de codage choisi est un sujet séparé, ce qui pourrait très bien être fait pour être un accès direct à l'indice direct efficace. Maintenant, même si la lexing, l'analyse et la recherche ne modifient pas en place, il existe de nombreux autres cas où ils le font - votre toupeur typique () / tolower () / Titlecase () / Mid () / gauche () / gauche () / droite () / Reverse () Il suffit de nommer que quelques cas courants peuvent tous être effectués sur place (avec quelques exceptions spécifiques locales). Même le remplacement peut


Généralement être fait en place en raison du fait que des objets de chaîne mutable réservent généralement plus de mémoire qu'elles utilisent (la plupart des pouvoirs d'utilisation de deux pour rendre la croissance globale amortie O (1)) en les rendant assez efficaces dans le cadre d'une analyse réelle.