Huh, I did F# for years with discriminated unions, and I guess I just assumed C# would have had them by now.<p>I know not everyone likes them, but for typed languages I find it extremely hard to go back to languages without ADTs of some kind. I do Java for my current job, and Java is generally fine enough, but it's a little annoying when I have to do whacky workarounds with wrapper classes to get something that would be done in three lines of F#.
Really excited for this proposal as it's been the main thing I have to apoligize for when extolling the values of C#. Outside of this it's hard to think of other major features C# lacks for a language.<p>Additionally, excited to now watch this go in and people on HN still act like C# is the same it was 10 years ago.
Can anyone explain why this is called "type unions"? I've never heard it named that before. It's a bit weird, because it's not a union across types (like ALGOL68), it appears to be a tagged union like in ML-family languages.<p>Is this just a case of "C# developers like to make up different names than established terminology"? (see: SelectMany, IEnumerable, etc.)
I’ve lost track of all of the red/blue/white/black pill color metaphors, but unions with exhaustive pattern matching is one of the toughest of all programming language features to live without once you become aware of it.<p>I’ve never felt like I’ve fully understood the implications of the expression problem <a href="https://en.wikipedia.org/wiki/Expression_problem" rel="nofollow">https://en.wikipedia.org/wiki/Expression_problem</a> but my best/latest personal hypothesis is that providing extension points via conventional polymorphism might be best suited for unknown/future clients who might extend the code, but unions with exhaustive pattern matching seem better suited for code that I or my team owns. I don’t typically want to extend that code. More often, I instead want to update my core data structures to reflect ongoing changes in my understanding of the business domain, more often than not using these Union-type relationships, and then lean on the compiler errors maximally to get feedback about where the rest of the imperative code now no longer matches the business domain data structures.
Is the terminology slightly off? AIUI TypeScript has type unions.<p>But this looks like a discriminated union which I'd recognise from F# or Haskell. The distinction I'd draw is that for a DU there are named case constructors. Yes?
As a long time C# dev, I feel like I’m missing something about this proposal. The use case for this doesn’t seem well defined to me. Could someone give me a real world example?<p>I’m pretty sure you can implement the example in this proposal by declaring an empty interface and having some record classes that “implement” it. Does that lose something that I’m not seeing?
> The interior layout of the union struct is chosen to allow for efficient storage of the data found within the different possible member types with tradeoffs between speed and size chosen by the compiler.<p>Having _attempted_ (and being bitten by) far too much black magic with C# unions in the past (using FieldOffset), there is an unfortunate situation here: aliasing a pointer/ref value and value is UB. This means that a struct union of a u64 and an object would need separate fields for each, wasting 8 bytes. That is, unless the ryujit/gc is updated with knowledge about this.
I always think it's a shame that instead of C# becoming a better OO language, they keep trying to become an uglier F#. IE, why is the syntax for multiple dispatch still so clunky?<p>I know I know, pseudo OO took over the world, and then people revolted against it, so the easiest thing to do to stay relevant is to become "slightly functional with curly braces", rather than to actually try and do OO well.
I'm currently using nested records with a private constructor in combination with the nuget package <a href="https://github.com/shuebner/ClosedTypeHierarchyDiagnosticSuppressor">https://github.com/shuebner/ClosedTypeHierarchyDiagnosticSup...</a> to make sure the switch types do not require a `_` case. This is essentially the desugared version of their "Union Classes" proposal. This already works very well. Still, I like this proposal because it would be nice if the nuget package would become unnecessary and the syntactic sugar is also nice to have.
how do people writing C# deal with its gazillian features? It seems easier (and more useful) to learn and master every language that it absorbs, rather than C# itself.
regarding ad hoc unions the article mentions this:<p><pre><code> Siamese pet = ...;
(Cat or Chihuahua) mostlyCats = pet;
Dog dog = (Dog)mostlyCats;
</code></pre>
<i>Note: This works for implemented interfaces too.</i><p>I am unsure what that section entails...<p>Let's say I have a function like this:<p><pre><code> void ConsumeAB<T>(T ab) where T: IA, IB;
</code></pre>
And implementing classes like this:<p><pre><code> class ABC : IA, IB {}
class ABD : IA, IB {}
</code></pre>
Will I be able to use this function like this:<p><pre><code> var items = new (ABC or ABD)[] { new ABC(), new ABD() };
foreach (var item in items)
{
ConsumeAB(item);
}
</code></pre>
In other words will the ad hoc union act as it would implement all interfaces that all cases have in common? My guess it won't work, as it gets lowered to code that uses object. Would a custom union help me here?
I very much hope to see this (or similar) in C# soon. It’s not make or break for me, but it would certainly help make for cleaner, smaller codebases — I’ve sorely missed it in the past, but only a couple times. My context is being a former hard-core C++ person who switched to .Net and AWS pretty-much cold turkey.<p>Edit: typo
That proposal doesn't mention how the union struct handles tearing under concurrent modification.<p>Tearing can cause memory safety issue. Variant A can have an integer field and variant B can have a reference field in the same offset. Tearing can cause it to treat an integer as reference.
What's the difference between this proposal and sealed classes in Kotlin? Looking at the definitions in the proposal these look functionaly similar. Haven't worked with C# in some years so suprised that this isn't already a language feature.
What would the rough timeframe be for seeing adoption of this into the language?<p>I was considering introducing the OneOf library into our codebase, but if this is < a year or so away it might not be worth the effort.
Does anyone also feel that any new feature in C# changes to a flame war between Java and C# :-)
I expected that before clicking the link, and came prepared :popcorn:
Every time the question of preferred programming languages comes up, I'm usually in the extreme minority with my preferences being Rust (for small/fast) and C# (for productive and easy, where GC is acceptable), a combination that doesn't seem to appeal to too many people.<p>But for the projects that fall right about in the middle where it could go either way and I could see either language working, I almost always pick rust with discriminated unions being the biggest reason. It's <i>incredibly hard</i> to go back to a language without even basic ADTs after seeing the light.
I don't have anything insightful to add, I just want to add my voice to the choir of people saying that after using sum types, working in a language without them feels unnecessarily restrictive and awkward.<p>If this feature were implemented, it would take C# to a top contender for a daily driver language for me, and would make me feel a lot more confident in choosing it for projects where the C# ecosystem is already present, such Godot's C# version.<p>I'm really excited about this proposal, and I don't know anything about C#'s development pace, but I'll be watching from the sidelines hoping I can use union types in production in 2025 or so.
I find it strange and slightly confusing that tey call it "union types". The correct term would be "sum types" or "discriminated union types", union types being the union of two types with no distinctive tag between the two cases. E.g. |Int ∪ Int| ≡ |Int|, while |Int + Int| ≡ 2 |Int|
It’s ironic when things like this get added back into C-styled languages that were intended to be easier than their predecessors.<p>Seems more confusing than useful. Wish they’d stop adding onto this ever expanding language.<p>It’s like these people get bored of plain old functions and objects, read an academic paper and go “i think I’ll add that next”.