language-ext v3.3.30 Release Notes
Release Date: 2019-11-09 // over 4 years ago-
🚀 In this release the code-generation story has been extended to support sum-types (also known as 'discriminated unions', 'union types', or 'case types').
Simply declare an
interface
with the attribute[Union]
where all methods declared in the interface return the type of the interface, i.e.[Union] public interface Maybe\<A\> { Maybe\<A\> Just(A value); Maybe\<A\> Nothing(); }
It has similar behaviour to this, in F#:
type Maybe\<'a\> =| Just of 'a | Nothing
In the above example, two case-types classes will be created
Just<A>
andNothing<A>
as well asstatic
constructor class calledMaybe
:var maybe = Maybe.Just(123); var res = maybe switch { Just\<int\> just =\> just.Value, Nothing\<int\> \_ =\> 0 };
This is the generated code:
public partial class Just\<A\> : LanguageExt.Record\<Just\<A\>\>, Maybe\<A\> { public readonly A Value; Maybe\<A\> Maybe\<A\>.Just(A value) =\> throw new System.NotSupportedException(); Maybe\<A\> Maybe\<A\>.Nothing() =\> throw new System.NotSupportedException(); public Just(A value) { Value = value; } } public partial class Nothing\<A\> : LanguageExt.Record\<Nothing\<A\>\>, Maybe\<A\> { Maybe\<A\> Maybe\<A\>.Just(A value) =\> throw new System.NotSupportedException(); Maybe\<A\> Maybe\<A\>.Nothing() =\> throw new System.NotSupportedException(); public Nothing() { } } public static partial class Maybe { public static Maybe\<A\> Just\<A\>(A value) =\> new Just\<A\>(value); public static Maybe\<A\> Nothing\<A\>() =\> new Nothing\<A\>(); }
👍 The generated code is relatively basic at the moment. It will be extended to support
abstract class
types and will auto-generate structural equality behaviour as well as other useful behaviours. But for now this is a super-quick way to generate the cases for a union-type and have a simple way of constructing them.The generated types are all
partial
and can therefore be extended trivially.Here's another simple example:
[Union] public interface Shape { Shape Rectangle(float width, float length); Shape Circle(float radius); Shape Prism(float width, float height); }
And the generated code:
public partial class Rectangle : LanguageExt.Record\<Rectangle\>, Shape { public readonly float Width; public readonly float Length; Shape Shape.Rectangle(float width, float length) =\> throw new System.NotSupportedException(); Shape Shape.Circle(float radius) =\> throw new System.NotSupportedException(); Shape Shape.Prism(float width, float height) =\> throw new System.NotSupportedException(); public Rectangle(float width, float length) { Width = width; Length = length; } } public partial class Circle : LanguageExt.Record\<Circle\>, Shape { public readonly float Radius; Shape Shape.Rectangle(float width, float length) =\> throw new System.NotSupportedException(); Shape Shape.Circle(float radius) =\> throw new System.NotSupportedException(); Shape Shape.Prism(float width, float height) =\> throw new System.NotSupportedException(); public Circle(float radius) { Radius = radius; } } public partial class Prism : LanguageExt.Record\<Prism\>, Shape { public readonly float Width; public readonly float Height; Shape Shape.Rectangle(float width, float length) =\> throw new System.NotSupportedException(); Shape Shape.Circle(float radius) =\> throw new System.NotSupportedException(); Shape Shape.Prism(float width, float height) =\> throw new System.NotSupportedException(); public Prism(float width, float height) { Width = width; Height = height; } } public static partial class ShapeCon { public static Shape Rectangle(float width, float length) =\> new Rectangle(width, length); public static Shape Circle(float radius) =\> new Circle(radius); public static Shape Prism(float width, float height) =\> new Prism(width, height); }
⚡️ > NOTE: The code-gen doesn't yet support .NET Core 3.0 - I'm still waiting for the Roslyn code-gen project to be updated. If it isn't forthcoming soon, I'll look for other options.