29 comments

[ 2.4 ms ] story [ 37.1 ms ] thread
F# leads the way and C# slowly catches up, as always. Yet for some reason, C# still gets all the mindshare.
I'm glad to finally see this making it's way into C#. Not so much because I want to use unions purely in C#. But because I want to be able to define them when interfacing with other languages.
I mean yes, but also: uh-oh. I'm looking forward to reading some code that is even more confusing than the code I'm already reading.

Not entirely convinced that I see the usecase that makes up for the potential madness.

AFAICT, this means you won’t be able to define Either<string, string>, which is definitely a thing you sometimes want to do.
(comment deleted)
I used to see some excitement around .net core several years ago. I haven’t heard or seen much in the wild. Is anyone using .net on systems other than windows nowadays?
I love C# and in every iteration we're getting more and more features to get C-like performance in a lot of scenarios. C# does it really well because if your problem isn't performance/memory-constrained, you can ignore these features and fallback on the language's natural ease of use.
I wish the syntax looked more like typescript. This will confuse my eyes for a while.
F# has had this for decades, C# is basically just slowly becoming F# with a C-style syntax. Not complaining though, most teams aren't switching languages so getting these features where people actually work is better than nothing.
C# is my strongest and favorite language. That said, it's frustrating that the C# framework ecosystem lacks solid options. MAUI is especially half-baked, and I'm really starting to doubt whether I should continue using XAML
Did Anders Hejlsberg die, or something?
Boxed, and needs complex incantations to avoid the boxing. Meh.
I've waited for union types on C# so long that I don't even care about syntax anymore. Just give us something that works. So, I appreciate the effort, I know it's taken at least a decade to get it into this shape, and much thought has gone into it. Kudos to the team.
Wow 2016 would have loved this news.
Most people don't know that there are fundamentally two different kinds of "union" types: "tagged unions" and "untagged unions". Now .NET is introducing tagged unions, but unfortunately they stick to the popular tradition of calling them just "unions", which greatly adds to the confusion.

To clarify, these tagged unions are fundamentally different from the untagged unions that can be found in languages like Typescript or Scala 3.

Tagged unions (also called "discriminated unions" or "sum types") are algebraic data types. They act as wrappers, via special constructors, for two (or more) disjoint types and values. So a tagged union acts like a bag that has two (or more) labelled ("tagged") slots, where each slot has exactly one type and exactly one of these slot can take a value.

Untagged unions are set theoretic (rather than algebraic) data types. They don't require wrapping via a special constructor. They behave like the logical OR. They are not disjoint slots of a separate construct. A variable or function x with the type "Foo | Bar" can be of type Foo, or Bar, or both. To access a Foo method on x, one has to first perform a typecheck for Foo, otherwise the compiler will refuse the method call (since x might only have the type Bar which would produce an exception). If a variable is of type A, it is also of type A|B ("A or B"). There are also intersection types (A&B) which indicate that something has both types rather than at least one, and complement/negation types (~A indicates that something is of any type except A). Though the latter are not implemented in any major language so far.

As a big user and fan of c# but this is a miss, as it always boxes value types.
About time. TypeScript and Rust proved how much cleaner code gets when you can model "this OR that" at the type level. The real test will be whether library authors start using them in public APIs or if they stay a curiosity.
If C# can get them then Golang can get them as well!

Come on Gophers! It's time.

Finally C# will have a more idiomatic way to represent this classic code example from “The Daily WTF” in 2005 —

    enum Bool 
    { 
        True, 
        False, 
        FileNotFound 
    };
See https://thedailywtf.com/articles/what_is_truth_0x3f_
About 12 years ago I went to go and work on some legacy C++ software when I was very green. We had a big code base and it had enum Bool { False = 0, True = 1 } everywhere. I thought it was a good idea to rationalise this since we had conversions all over the place to the modern bool type.

So I suggested it, got a PR up (bit painful) it got reviewed, went in, everything worked fine, and we came about a week towards releasing the product (6 monthly releases) before someone noticed that we couldn’t load files from previous versions. Turned out that we wrote lots of these old Bool types to binary data files and so the 4 byte data was now being read as 1 byte data. Oops. Reverted the whole lot. Lesson in humility!

Why would the default language-level union keyword implementation force boxing? Seems like a crazy decision if it could just also implement the HasValue/TryGet itself and avoid it?
Wow! I remember unions back in my Uni days. So many years ago.
Shame it'll be like 3 years until System.Text.Json sees support for serialization or exporting schemas for them..
C# is such an underrated language.

A nice balance of language features and legibility.

sadly there is no ad hoc way of defining them. I do not care if they are boxed. I just want to say Success or Error1 or Error 2. Maybe I can live with or | or other stuff but not having ad hoc unions is basically not cool.