Proposition officielle des Type Unions en C#
(github.com/dotnet)Résumé
Il s’agit d’un document proposant les unions de types (ou unions discriminées) en C#.
Motivation
- Lors du développement logiciel, les valeurs stockées dans une variable ne sont pas toujours du même genre.
- Par exemple, lorsque les définitions d’un client et d’un fournisseur ne partagent qu’une partie de leurs propriétés, il peut être nécessaire d’effectuer des opérations similaires sur ces deux types.
- L’héritage peut résoudre le problème, mais ne convient pas à toutes les situations.
- Il est nécessaire, en C#, de disposer d’un moyen de stocker un nombre limité de types différents dans une même variable.
- D’autres langages offrent déjà cette fonctionnalité.
Solution
- La manière la plus appropriée d’implémenter les unions de types en C# peut être envisagée comme une hiérarchie reposant sur une classe de base abstraite.
- Cependant, cette approche présente des problèmes, comme les contraintes de hiérarchie ou l’impossibilité de représenter une union de types sans lien entre eux.
- Plusieurs sortes d’unions peuvent être nécessaires, et cette proposition les classe en quatre catégories.
Standard - classe union
Déclaration
- Une classe union se déclare de manière similaire à un enum.
- Chaque membre peut avoir des variables d’état.
Création
- Elle est créée en assignant une instance d’un type membre.
Déconstruction
- Elle se décompose via des tests de type et le pattern matching.
Exhaustivité
- Si tous les types membres sont pris en compte dans une expression ou une instruction
switch, un cas par défaut n’est pas nécessaire.
Nullabilité
- Il est possible d’inclure
nullen utilisant la notation standard de nullabilité.
Implémentation
- Une classe union est implémentée comme une classe record abstraite.
Spécialisation - struct union
Déclaration
- Elle se déclare de manière similaire à une classe union, mais avec le mot-clé
structen plus.
Création
- Elle est créée en assignant une instance d’un type membre.
Déconstruction
- Elle se décompose via des tests de type et le pattern matching.
Exhaustivité
- Si tous les types membres sont pris en compte dans une expression ou une instruction
switch, un cas par défaut n’est pas nécessaire.
Nullabilité
- Il est possible d’inclure
nullen utilisant la notation standard de nullabilité.
Valeur par défaut
- Une struct union peut être dans un état non défini lorsqu’elle n’est pas assignée ou qu’elle reçoit sa valeur par défaut.
Implémentation
- Une struct union est implémentée comme une structure, et les types membres sont implémentés comme des record structs imbriqués.
Temporaire - union ad hoc
Syntaxe
- Une union ad hoc est référencée à l’aide de la syntaxe de pattern
or.
Nommage
- Il est possible de donner un nom commun à une union ad hoc à l’aide d’un alias
usingde fichier ou global.
Création
- Elle est créée en assignant une instance d’un type membre.
Déconstruction
- Elle se décompose via des tests de type et le pattern matching.
Exhaustivité
- Si tous les types membres sont pris en compte dans une expression ou une instruction
switch, un cas par défaut n’est pas nécessaire.
Nullabilité
- Il est possible d’inclure
nullen utilisant la notation standard de nullabilité.
Interchangeabilité
- Les unions ad hoc ayant les mêmes types membres sont interchangeables.
Unions définies par l’utilisateur
- Il est possible de déclarer des types union qui ne peuvent pas être exprimés comme classe union ou struct union.
- L’attribut
Closedpermet de fermer une hiérarchie. - L’attribut
Unionpermet une implémentation sous forme de wrapper struct.
Unions courantes
Option
- Il s’agit d’une union sous forme de structure qui représente une valeur pouvant être présente ou absente.
Result
- Il s’agit d’une union sous forme de structure permettant à une fonction de renvoyer soit un résultat réussi, soit une erreur.
Propositions associées
Hiérarchie fermée
- L’attribut
Closedpermet de déclarer, pour un type de base abstrait, un ensemble fermé de sous-types.
Valeurs singleton
- Les types dotés d’un attribut singleton peuvent être utilisés comme valeurs dans un contexte non typé.
Raccourci pour les membres imbriqués
- Il est possible d’utiliser des noms non liés pour les lier aux membres statiques ou aux types imbriqués du type cible.
Le récapitulatif de GN⁺
- Ce document propose les unions de types en C# et fournit un moyen de stocker plusieurs types dans une variable selon différents contextes.
- Il s’agit d’une tentative d’introduire en C# une fonctionnalité déjà présente dans d’autres langages.
- Cela peut aider les développeurs à améliorer la lisibilité et la maintenabilité du code.
- Parmi les autres langages offrant une fonctionnalité similaire, on peut citer F#.
1 commentaires
Avis Hacker News
J’utilise des unions discriminées en F# depuis longtemps, et je pensais que C# en avait aussi
Le terme « union de types » m’est peu familier
En tant que développeur C# de longue date, je trouve que le cas d’usage de cette proposition n’est pas clair
TypeScript a des unions de types
Programmer sans unions compatibles avec le pattern matching devient difficile
J’ai déjà utilisé des unions C# avec des offsets de champ
u64et un objet peut nécessiter un champ séparé, ce qui peut gaspiller 8 octetsAvec des constructeurs privés et un package nuget, on peut faire en sorte qu’un type switch n’exige pas de cas
_La proposition ne mentionne pas comment une struct union gère le tearing lors de modifications concurrentes