ImmutableArray, une alternative plus rapide à ImmutableList pour les scénarios de lecture seule, avec accès par index, est disponible dans la dernière version des collections immuables pour .Net. ImmutableList a une approche équilibrée : grâce à sa structure interne complexe, ajouter un élément est une opération de complexité O(log n) (NdT: ImmutableList est implémentée à l'aide d'un arbre binaire). De même, accéder à un élément par index peut prendre O(log n).
ImmutableArray est beaucoup plus simple. C’est une structure qui enveloppe un tableau. D’après ildasm, la structure ne possède aucun autre champ, ce qui signifie que la lecture s’effectue en O(1). A l’inverse, ajouter un élément nécessite une copie complète du tableau sous-jacent, ce qui en fait une opération de complexité O(n). Immo Landwerth fait les recommandations suivantes :
Les raisons d’utiliser ImmutableArray :
- Mettre à jour la donnée est rare ou le nombre d’éléments est petit (<16)
- Vous itérez sur les données dans des sections de code aux performances critiques
- Vous avez de nombreuses instances de collections immuables et vous ne pouvez pas conserver les données dans une structure de type arbre
Les raisons de continuer à utiliser ImmutableList :
- Mettre à jour les données est courant ou le nombre d’éléments à stocker est important
- Les performances de mise à jour sont plus critiques que les performances d’itération
Etant un type valeur, ImmutableArray peut être créé sans être explicitement initialisé. Quand cela se produit, la structure détecte le pointeur null interne et agit comme si le tableau avait une taille de zéro.
Changements non rétro compatibles
Les collections immuables sont en cours de développement et des modifications non rétro compatibles peuvent arriver de temps en temps. Cette fois ci, la fonction Create(IEnumerable items) a été renommée en « From ».
Immo s’explique :
Nous avons découvert que la surcharge qui accepte IEnumerable peut avoir un comportement surprenant. Vous pourriez penser qu'il est possible de créer des collections immuables à partir d'autres collections en utilisant cette surcharge.
En réalité, à la place de créer une ImmutableList, vous finissez avec une ImmutableList> car la résolution de la surcharge sélectionne la méthode prenant en paramètre params T[] plutôt que de convertir implicitement List en IEnumerable. Pour cette raison, nous avons décidé de supprimer l’ambiguïté en renommant toutes les méthodes de fabrique qui opèrent sur IEnumerable en From(…).
A l’origine, IImmutableList incluait une propriété ValueComparer ainsi qu’une méthode WithComparer associée. Afin de garder ImmutableArray une simple enveloppe, il était nécessaire de les supprimer de l’interface IImutableList.
Autres modifications
TryGetValue a été ajouté à IImmutableSet. Ceci est nécessaire si on travaille avec un comparateur tel que StringComparer.OrdinalIgnoreCase lorsque vous voulez connaître la valeur actuelle dans l’ensemble et non pas simplement savoir si une valeur équivalente est déjà présente.
Les collections immuables sont encore au stade de préversion et n’ont pas une licence permettant de les utiliser en production. Elles sont pour le moment fournies pour .Net 4.5, les applications Windows Store, Windows phone 8 et les Portable Class Libraries.
Notes sur les performances des tableaux
Jon Skeet a récemment effectué des tests de performance sur les tableaux et a obtenu des résultats intéressants. En effet, ajouter une enveloppe autour d'un tableau peut rendre l'écriture dans ce dernier plus performante. Ecrire un tableau de 100 chaînes de caractères 100 millions de fois prend 40,843 secondes tandis que la version enveloppée par une struct s'exécute en 29.338 secondes. La lecture est comparable, le tableau prenant 12 secondes et le tableau enveloppé 11.843 secondes.
Les raisons de ces différences datent de Java. En Java, les tableaux sont covariants, ce qui signifie que vous pouvez passer un String[] a n'importe quel paramètre ou variable qui s'attend à recevoir un Object[]. La CLR, le runtime de .Net, a été conçu pour supporter java ce qui explique la présence des tableaux covariants (NdT: Plus d'informations sur le blog d'Eric Lippert). A cause de cela, la CLR doit effectuer une vérification du type à chaque fois qu'une écriture à lieu dans un tableau. L'enveloppe écrite par Jon Skeet n'est pas identique à celle utilisée dans la classe ImmutableArray mentionnée précédemment. En interne, elle enveloppe chaque élément dans une structure. Comme cette structure ne contient qu'un pointeur, elle n'est pas plus grosse qu'une référence habituellement stockée dans un tableau. Mais le design permet au compilateur juste à temps de la CLR de ne pas effectuer les vérifications de type.