Possibility of Discriminated Unions in C#: Functional Programming in .NET

preview_player
Показать описание
Curious about discriminated unions and their place in C#? That is a modeling tool often seen in functional programming. It lets you create a type that can be one of several predefined options but cannot be extended further. In other words, they offer a way to create a variable that can legitimately hold different types of data.
But, how does that translate into C# and .NET? And, by the same token, how does functional programming fit in? First of all, the current C# syntax does not support discriminated unions. But, as you will learn from the video, it doesn't take more than disciplined coding and the use of existing elements of the C# syntax - primarily records - to write clean functional code in the middle of your object-oriented domain model!
In this video, we will extend an ASP.NET Core application to demonstrate how a discriminated union can be a better fit than a traditional object-oriented model in certain situations. We show how this functional concept can be used to develop a complex feature, with the goal of making your code more expressive and manageable.
From tackling domain modeling to dealing with complex injectable strategies, this video takes you on a tour-de-force functional modeling in C#, based on the use of discriminated unions.
Don't miss out on this opportunity to deepen your programming skills with C# and .NET, learn about discriminated unions, and see the potential of C# and .NET functional programming.

Thank you so much for watching! Please like, comment & share this video as it helps me a ton!! Don't forget to subscribe to my channel for more amazing videos and make sure to hit the bell icon to never miss any updates.🔥❤️

⭐ Learn more from video courses:

▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬

⭐ CONNECT WITH ME 📱👨

▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
👨 About Me 👨
Hi, I’m Zoran, I have more than 20 years of experience as a software developer, architect, team lead, and more. I have been programming in C# since its inception in the early 2000s. Since 2017 I have started publishing professional video courses at Pluralsight and Udemy and by this point, there are over 100 hours of the highest-quality videos you can watch on those platforms. On my YouTube channel, you can find shorter video forms focused on clarifying practical issues in coding, design, and architecture of .NET applications.❤️
▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
⚡️RIGHT NOTICE:
The Copyright Laws of the United States recognize a “fair use” of copyrighted content. Section 107 of the U.S. Copyright Act states: “Notwithstanding the provisions of sections 106 and 106A, the fair use of a copyrighted work, including such use by reproduction in copies or phono records or by any other means specified by that section, for purposes such as criticism, comment, news reporting, teaching (including multiple copies for classroom use), scholarship, or research, is not an infringement of copyright." This video and our youtube channel, in general, may contain certain copyrighted works that were not specifically authorised to be used by the copyright holder(s), but which we believe in good faith are protected by federal law and the Fair use doctrine for one or more of the reasons noted above.

#dotnet #csharp #functionalprogramming
Рекомендации по теме
Комментарии
Автор

That "But I do, I'm sorry, it won't stop" is powerful

Bankoru
Автор

Great! The only catch is that this is just an emulated DU and C# doesn't handle it with the confidence and elegance of F#. For those who don't have a love affair with F# like I do: In F#, the match expression would ensure that all cases of a DU are handled: As long as there is a match expression that does not handle all cases, it just won't compile. Anyway, thanks for this nice alternative!

arnofahrenkamp
Автор

I've been begging for discriminated unions since 2012, when I first glanced into F#. It really saddens me we didn't get them earlier in C#, but at least the .NET team confirmed they are coming. Fingers crossed for .NET 10?

opterios
Автор

You are winning me over to functional programming. Very nice explanation, mixing both example, theory and exhortation.

codingbloke
Автор

once you go functional, you'll never go back

able
Автор

Great video, Zoran! It really got me into thinking about an ideal approach for this particular problem. It's a classic objects vs data structures dilemma as the discriminated unions are nothing more than data structures with a few additional constraints and compile-time checks. Obviously, there are no silver bullets - each has its own strengths and weaknesses. With objects, it's easy to add new types but difficult to add new polymorphic behavior without changing all the derived classes. With data structures, it's the exact opposite: easy to add new functionality to the family of data structures, but difficult to add new data structures without changing the existing functions that operate on them.

Having said that, I'd argue this particular example is better suited for objects and OO in general because the number of citation segment types will likely grow as the domain evolves (for instance, it makes sense to add a publisher segment, academic institution segment, journal segment, etc) while the number of functions will likely remain the same (citation segments are mostly for display purposes). I personally don't value syntactic sugar over a well-structured and expressive code so closing the consumption code against adding new segment types is what seems like a better choice.

The need to separate the UI code from the domain is a slight inconvenience, but nothing that a little bit of reflection can't fix. Keeping the same CitationSegment domain classes, I'd implement something like this in the UI layer:

public interface
{
HtmlString ToHtml();
}

public class author)
:
{
public HtmlString ToHtml()
=> new HtmlString($"<a
}

public class title)
:
{
public HtmlString ToHtml()
=> new HtmlString($"<a
}

public class segment).
:
{
public HtmlString ToHtml()
=> new
}

public static class CitationSegmentExtensions
{
public static HtmlString ToHtml(this CitationSegment segment)
{
Type converter =
return
}

private static Type GetMatchingConverter(this CitationSegment segment)
{
return
.FirstOrDefault(f =>
?? typeof(DefaultConverter);
}
}

public static class TypeExtensions
{
public static IEnumerable<Type> GetImplementers(this Type interfaceType)
=> => && !t.IsInterface);

public static bool Type type, Type argumentType)
=> type.GetConstructors().Any(c => c.GetParameters().Count() == 1 && == argumentType);

public static T Instanciate<T>(this Type type, params object[] constructorArgs)
=> (T)Activator.CreateInstance(type, constructorArgs);
}

No ugly if statements, no cryptic switch statements, no syntax ninjitsu, the UI consumption code becomes trivial, classes are small & boring & easy to understand and test, and most importantly no need to change anything when a new segment gets introduced. If you don't add a new ICitationSegmentHtmlConverter, the default one will do just fine. If the performance is a concern, converters can be cached. OCP and SRP principles in action. The drawback: you need to use reflection to find the right converter. A rather small price to pay for all the benefits you get. Cheers!

milosmrdovic
Автор

When video started I think about pure C union structure data(struct where all fields have one start address).but.. its so exotic😀

EugeneS-RU
Автор

So good, you're provoking me to up my game.

nickbarton
Автор

Another banger of a videos. Fantastic! Fantastic!! videos.
Me being a die hard OOP guy. I will argue the OOP implementation of this concept is much stronger.
Why do you prefer this method over the double dispatch?
I even feel like your implementation is quite similar to double dispatch in OOP but instead of using a reduce, you are using extension method.
Another advantage of the OOP style implementation is that it would even work on graph object. meaning we can reduce a type with graph like property to any generic type.

here is example of how I would implement this feature you are working on from concept I learned from OOP.


public abstract class CitationSegment{
public string Text {get; set;}
CitationSegment(string text) this.Text = text;
public abstract T Reduce<T>(ITransformer transformer);
}

public class BookAuthorSegment : CitationSegment{
public string AuthorId
public string Name
public override T Reduce<T>(ITransformer<T> transformer) => transformer.Transform(this);
}

public class BookTitleSegment: CitationSegment{
public string BookId
public string Title
public override T Reduce<T>(ITransformer<T> transformer) => transformer.Transform(this);
}


public interface ITransformer<out T>
{
T Transform(BookAuthorSegment segment);
T Transform(BookTitleSegment segment);
}

public FormatWithBracket: ITransformer<string>{
string Transform(BookAuthorSegment segment){
//write the transformation code -> BookAuthorSegment <-
}

string Transform(BookTitleSegment segment){
//write the transformation code -> BookTitleSegment <-
}
}

public FormatWithDashes: ITransformer<string>{}//

moneymaker
Автор

This is the problem I am trying to solve this week. Timely.

bitmanagent
Автор

Zorvan, you have a very soothing voice! If I may, I'd like to recommend The Rust Programming Language to you. It has first class support for both imperative and declarative paradigms, which allows you to pick and choose what suits you in a certain situation. Many patterns are welcomed and situationally finding the best match is highly encouraged rather than trying to apply a single pattern to a whole codebase. You'll be happy to see discriminated unions make an appearance as enums, along with very powerful pattern matching utilities, among other things. Hope to see you try it!

dyslexicsteak
Автор

This is all great stuff. I would personally make all union members 'sealed' as well - So as to strongly discourage further derived types, and to make the intention of DU's clear.

andrewthompson
Автор

Thank you, Iliked the description and the way you present.

yogabija
Автор

Actually, there is a way to restrict inheritance to a closed set of classes (same goes for records which are essentially classes except for "record struct").

Give the base class a private parameterless constructor.

Define all children classes as nested inside the base class, so they have access to this constructor.

Now trying to derive the base from outside it will result in a compiler error.

cover
Автор

Keep in mind that this is simpler, but more limited, than a traditional OOP solution. The hint is in having to know all the subtypes at compile time. In OOP you could (theoretically) get new instances of your objects at runtime from unknown 3rd parties and they will 'work' since it has all it needs to be 'pluggable'. (Spoiler: you'll almost certainly have to write some kind of 'plugin' architecture since OOP alone can't do it, but you still get all the OOP baggage)

Of course, in practice, are you really doing that? Running code that hasn't been tested together is sketchy at best, running code you've never even seen feels... wonderfully naive.

adambickford
Автор

I'm already begging, please, give me Sum Types, or at-least Discriminated Unions!

MagicNumberArg
Автор

You say around 7:30 that the greatest enemy of DUs is adding a type. I don't think that's true. It's actually an advantage of DUs, *properly implemented*: when you add a type, every single place where you aren't handling that type throws a compile error. Given that the code can't write itself, I think that's the best user experience you could ask for!

nickcorrado
Автор

The very first library I add to a new project is OneOf, which emulates a DU quite elegantly until we have native support.

phyberoptyk
Автор

You said after watching this video I would be begging for C# to have extra syntax to support discriminated unions. But you demonstrated discrirminated unions, so I don’t know what you think we’re missisng. Maybe we need to see what F# does as an exact analagy to see how it’s cleaner.

abj
Автор

Thank you so much for the video. I am writing a plenty of code on frontend and was able to use this technique right away at my code. There can be complex rendering logic based on business requirements and using set of distriminitated states enhance readebility, specifiacally I find it easier scan the sequence of states in one column and then focus on one area then hold the mental web of ifs and elses clauses spread in the code.

There is one thing that I want to ask if I understand it correctly. This technique could look as breaking one of the OOP principles that says that consumer should depedent on the interface rather than concrete implementation. And now, If I am manually casting and inspecting the interface into all possible types that kinda defeat the point having the interface in the first place right? But that is coming from OOP perspective. From the FP perspective this is just implementation trick and I am not breaking any guidelines?

Thanks again for your content. Looking forward for another video.

secury