C#の Type Unions 公式提案
(github.com/dotnet)要約
C#における型ユニオン(または判別共用体)を提案する文書。
動機
- ソフトウェア開発では、変数に保存する値が常に同じ種類とは限らない。
- たとえば、顧客とサプライヤーの定義が一部のプロパティだけを共有している場合、2つの型に対して類似した処理を行う必要があることがある。
- 継承によって解決できるが、あらゆる状況に適しているわけではない。
- C#では、限られた数の異なる型を同じ変数に保存できる方法が必要である。
- 他の言語では、すでにこのような機能が提供されている。
解決策
- C#でユニオン型を実装する最も適切な方法は、抽象基底クラスを用いた階層構造として考えることができる。
- しかし、階層構造の制約や、無関係な型のユニオンを表現できないといった問題がある。
- 複数種類のユニオンが必要になる可能性があり、この提案では4つのカテゴリに分類している。
標準 - ユニオンクラス
宣言
- ユニオンクラスは enum に似た形で宣言される。
- 各メンバーは状態変数を持つことができる。
生成
- メンバー型のインスタンスを割り当てて生成される。
分解
- 型テストとパターンマッチングによって分解される。
網羅性
- すべてのメンバー型が switch 式または switch 文で考慮されていれば、デフォルトケースは不要である。
Null 許容性
- 標準の Null 許容表記を使って Null を含めることができる。
実装
- ユニオンクラスは抽象レコードクラスとして実装される。
特化 - ユニオン構造体
宣言
- ユニオンクラスと似た形で宣言されるが、
structキーワードが追加される。
生成
- メンバー型のインスタンスを割り当てて生成される。
分解
- 型テストとパターンマッチングによって分解される。
網羅性
- すべてのメンバー型が switch 式または switch 文で考慮されていれば、デフォルトケースは不要である。
Null 許容性
- 標準の Null 許容表記を使って Null を含めることができる。
デフォルト値
- ユニオン構造体は、未割り当てまたはデフォルト値が割り当てられた場合、未定義状態になる可能性がある。
実装
- ユニオン構造体は構造体として実装され、メンバー型は入れ子のレコード構造体として実装される。
一時的 - 一時ユニオン
構文
- 一時ユニオンは
orパターン構文を使って参照される。
命名
- ファイルまたはグローバル using エイリアスを使って、一時ユニオンに共通の名前を付けることができる。
生成
- メンバー型のインスタンスを割り当てて生成される。
分解
- 型テストとパターンマッチングによって分解される。
網羅性
- すべてのメンバー型が switch 式または switch 文で考慮されていれば、デフォルトケースは不要である。
Null 許容性
- 標準の Null 許容表記を使って Null を含めることができる。
相互交換性
- 同一のメンバー型を持つ一時ユニオンは相互交換可能である。
ユーザー定義ユニオン
- ユニオンクラスやユニオン構造体として指定できないユニオン型を宣言できる。
Closed属性を使って階層構造を閉じることができる。Union属性を使って構造体ラッパーとして実装できる。
共通ユニオン
Option
- 値が存在する場合も存在しない場合もあることを表す構造体ユニオンである。
Result
- 関数から成功結果またはエラーを返す構造体ユニオンである。
関連提案
閉じた階層構造
Closed属性を使って、抽象基底型に対して閉じたサブタイプ集合を宣言する。
シングルトン値
- シングルトン属性を持つ型は、非型コンテキストで値として使用できる。
入れ子メンバー短縮記法
- バインドされていない名前を使って、対象型の静的メンバーや入れ子型にバインドできる。
GN⁺の整理
- この文書は C#における型ユニオンを提案しており、さまざまな状況で変数に複数の型を保存できる方法を提供する。
- 他の言語ですでに提供されている機能を C#にも導入しようとする試みである。
- 開発者がコードの可読性と保守性を高めるのに役立つ可能性がある。
- 似た機能を提供する他言語の例としては F# がある。
1件のコメント
Hacker Newsのコメント
F#で判別共用体を使ってきたので、C#にもあるものだと思っていた
「型ユニオン」という用語に馴染みがない
長年のC#開発者として、この提案のユースケースが明確ではないと感じる
TypeScriptには型ユニオンがある
パターンマッチ可能なユニオンがないとプログラミングが難しくなる
C#のユニオンでフィールドオフセットを使った経験がある
u64とオブジェクトの構造体ユニオンでは別個のフィールドが必要になり、8バイトを無駄にすることがある非公開コンストラクタとnugetパッケージを使って、スイッチ型で
_ケースを不要にしているユニオン構造体が同時更新時のティアリングをどう扱うのかには触れられていない