-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Record struct union support #101
Comments
Can we make the record struct |
I checked some examples and here are my 2 cents. I remember reading a discussion somewhere in F# GitHub issues or RFCs the struct DU implementation. It mentioned that Rust implemented it in a smarter way by storing less data and reusing fields. Unfortunately, I can't find the discussion now and I forgot how it's properly called. Here's what I mean. Consider your Shape example. The size of Instead you could store just 2 private For reference types you could store an Obviously, it gets much more difficult with generics and you may want to fallback to the way you implemented it so far or ban generics for struct unions. To be honest it's not the strongest point of C# type inference anyways. It's rather tiring to type Also important to notice, I'm not that proficient in lower level stuff. I would definitely double check my claims :) |
i thought about it and you can support struct just fine, both [Union]
public partial readonly record struct Shape<T, T1, T2>
{
public static partial Shape Rectangle (T value) // note that that case type now use Base union directly rather than struct
public static partial Shape Circle(T1 value, T2 value)
}
//got generated as
partial readonly record struct Shape<T, T1, T2>
{
private enum ShapeField: byte //adjust base on number of case
{
Rectangle, Circle
}
private readonly T value1; // Rectangle value
private readonly T1 value2; // both value of Circle
private readonly T2 value3;
private ShapeField _flag; // store flag
private Shape(ShapeField flag ,T value = default!, T1 value1 = default!, T value2 = default) // private constructor, prevent other to construct
public static partial Shape Rectangle(T vale) => new Shape(ShapeField.Rectangle, value ); // create case
// ...
}
//helper class
public static class ShapeStatic
{
public static Shape<T,T1,T2> Rectangle<T,T1,T2>(T value) => Shape<T,T1,T2>.Rectangle(value);
} |
@NotAsea 100% agree. I have a prototype with almost that exact implementation. The only issue I'm trying to solve is preserving the current method of instantiating a union variant with a simple |
well with my code above you already can using static Dunet.Helper.Shape // namspace of generated ShapeStatic
var shape = Retangle(123); // Rectangle is static method , but i thought other problem that it seem not align with your |
The problem I was running into is that the static method collides with the variant type, since, at least with the current implementation, the type is declared within the union struct. // User writes this.
[Union]
public partial record struct Shape
{
public partial record struct Circle(double Radius);
}
// Generator creates this.
// But the `Circle()` method collides with the variant declaration above.
public partial record struct Shape
{
public static Shape Circle(double radius) => ...;
} |
The problem is if you still decide embed struct variant inside base struct union, you will cause your struct container very large and defeat its benefit compare to record class (heck even make it slower if value is very big), and of course increase complexity too. My current thought is using static method as variant directly and generator can retrieve all their value and just generate necessity backing field and a simple flag to switch, it even has benefit as if variant value is same type as value of other variant we can reuse backing field of another variant thus reduce memory need . (but loose ability to use switch statement/expression) Back to our problem, my solution is generate an additional static class for our union and instruct user to using static that helper class so they can just public partial readonly struct Shape<T,T1,T2>
{
// sniff
}
public static class Shape
{
public static Shape<T, T1, T2> Circle<T, T1, T2>(T1 value1, T2 value1) => new Shape.Circle(value1, value2);
}
// user code
using static Shape
var shape = Circle(1,3); note that this only work if our struct union is generic |
We should support declaring unions as
record structs
for consumers that want value semantics and reduced memory allocations. For example:Mixing and matching structs and classes should not be allowed.
Design note: Since using structs we cannot use
abstract
and inheritance to resolve the union type. We'll have to use a private discriminant like anenum
to support it and switch on it when matching.The text was updated successfully, but these errors were encountered: