fsharp / fsharp/fslang-suggestions
Interop with C# Union Types and Closed Hierarchies
- Dominant language
- No language data
- Stars
- 373
- Forks
- 21
- PR merge metrics
- No merged PRs in 30d
Description
**I propose we** add interop support between F# discriminated unions and C#'s upcoming union types / closed hierarchies, enabling exhaustive pattern matching across the language boundary in both directions.
Full design discussion: **[https://github.com/fsharp/fslang-suggestions/discussions/1463]**
> **Why a separate discussion?** C# unions is not one feature — it's a [broad umbrella](https://github.com/dotnet/csharplang/issues/9662) of 10 interlinked proposals (type unions, closed hierarchies, closed enums, case declarations, standard unions, target-typed access, inference features, type-value conversion). On the F# side, discriminated unions compile to 7 different IL layouts depending on case count, struct/ref, and attributes — each with different interop characteristics. The resulting matrix of "which C# feature × which F# layout" is too large for a single issue thread. The discussion has per-topic threads so each combination can be discussed independently.
**The existing way of approaching this problem in F# is** manually calling `.Value` on C# union types with no exhaustiveness, and C# consumers using `.Tag` switch + casts on F# DUs with no exhaustiveness.
## Scope
This covers F#'s response to the C# union feature family:
| C# Feature | F# Action | Discussion |
|------------|-----------|------------|
| [Type unions](https://github.com/dotnet/csharplang/blob/main/proposals/unions.md) (on Roslyn main) | Recognize `[Union]`, auto-unwrap `Value`, exhaustive match | [Topic A](https://github.com/fsharp/fslang-suggestions/discussions/1463#discussioncomment-16272820) |
| [Closed hierarchies](https://github.com/dotnet/csharplang/blob/main/proposals/closed-hierarchies.md) | Recognize `[Closed]`, emit `[Closed]` on F# DUs | [Topic B](https://github.com/fsharp/fslang-suggestions/discussions/1463#discussioncomment-16272821) |
| [Closed enums](https://github.com/dotnet/csharplang/blob/main/proposals/closed-enums.md) | Recognize + declare `[]` enums | [Topic C](https://github.com/fsharp/fslang-suggestions/discussions/1463#discussioncomment-16272823) |
| [Case declarations](https://github.com/dotnet/csharplang/blob/main/proposals/case-declarations.md) | Covered by closed hierarchies | [Topic D](https://github.com/fsharp/fslang-suggestions/discussions/1463#discussioncomment-16272824) |
| [Standard unions](https://github.com/dotnet/csharplang/blob/main/proposals/standard-unions.md) (`Union`) | Relationship to `Choice<'T1,'T2>` | [Topic E](https://github.com/fsharp/fslang-suggestions/discussions/1463#discussioncomment-16272825) |
| [Target-typed access](https://github.com/dotnet/csharplang/blob/main/proposals/target-typed-static-member-access.md) | `open type` + possible F# equivalent | [Topic F](https://github.com/fsharp/fslang-suggestions/discussions/1463#discussioncomment-16272826) |
| [Type value conversion](https://github.com/dotnet/csharplang/blob/12e6f5b0d512d15d32c8e7ae95674bd070b2758f/meetings/working-groups/discriminated-unions/type-value-conversion.md) | Type-as-value resolution | [Topic G](https://github.com/fsharp/fslang-suggestions/discussions/1463#discussioncomment-16272827) |
Also related: [target-typed inference](https://github.com/dotnet/csharplang/blob/main/proposals/target-typed-generic-type-inference.md), [ctor inference](https://github.com/dotnet/csharplang/blob/main/proposals/inference-for-constructor-calls.md), [pattern inference](https://github.com/dotnet/csharplang/blob/main/proposals/inference-for-type-patterns.md) — F# already handles these.
C# [umbrella issue](https://github.com/dotnet/csharplang/issues/9662) · [proposals overview](https://github.com/dotnet/csharplang/blob/main/meetings/working-groups/discriminated-unions/union-proposals-overview.md) · [Roslyn test plan](https://github.com/dotnet/roslyn/issues/81074) (notes "Ping F# as FYI")
## Pros and Cons
**Advantages:** Exhaustive pattern matching across F#/C# boundary. F# stays current with .NET. Natural extension of F#'s existing DU strength.
**Disadvantages:** Compiler complexity. C# spec still in preview (risk of churn).
## Extra information
**Estimated cost (XS, S, M, L, XL, XXL):** L
**Related suggestions:**
- [#538](https://github.com/fsharp/fslang-suggestions/issues/538) — Erased type-tagged anonymous union types
- [#1215](https://github.com/fsharp/fslang-suggestions/issues/1215) — Kotlin-like sealed classes
- [#1052](https://github.com/fsharp/fslang-suggestions/issues/1052) — Safe enums
- [#902](https://github.com/fsharp/fslang-suggestions/issues/902) — Deconstruct on DUs for C#
- [#606](https://github.com/fsharp/fslang-suggestions/issues/606) — Typed union cases
## Affidavit (please submit!)
Please tick these items by placing a cross in the box:
- [x] This is not a question (e.g. like one you might ask on [StackOverflow](http://stackoverflow.com)) and I have searched StackOverflow for discussions of this issue
- [x] This is a language change and not purely a tooling change (e.g. compiler bug, editor support, warning/error messages, new warning, non-breaking optimisation) belonging to [the compiler and tooling repository](https://github.com/dotnet/fsharp)
- [x] This is not something which has obviously "already been decided" in previous versions of F#. If you're questioning a fundamental design decision that has obviously already been taken (e.g. "Make F# untyped") then please don't submit it
- [x] I have [searched both open and closed suggestions on this site](http://github.com/fsharp/fslang-suggestions/issues) and believe this is not a duplicate
Please tick all that apply:
- [x] This is not a breaking change to the F# language design
- [x] I or my company would be willing to help implement and/or test this
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with discussion 1463 and its per-topic threads, then read the linked C# union, closed-hierarchy, enum, and related proposal documents. Compare those proposals with the F# discriminated-union layouts described in the issue; done means reaching an agreed design and scope for cross-language exhaustive matching, not just selecting one obvious code change.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp, fsharp
- Domain
- compilers
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100