mknejp / dotvariant Goto Github PK
View Code? Open in Web Editor NEWA type-safe and space-efficient sum type for C# (comparable to discriminated unions in C or C++)
Home Page: https://twitter.com/mknejp
A type-safe and space-efficient sum type for C# (comparable to discriminated unions in C or C++)
Home Page: https://twitter.com/mknejp
Hello,
in Dispose method always throw exception Result has encountered an internal error. Please file...
.
Example code:
[Variant]
partial class Result
{
static partial void VariantOf(object result, Exception exception, IDisposable handle);
}
Usage:
using Result result = Result.Create(new Diposable());
[Variant]
readonly partial struct SceneObjectParameter
{
static partial void VariantOf(
double @double,
float @float,
int @int
);
}
internally uses
private readonly struct Union
{
double @double;
float @float;
int @int;
}
but a more space-efficient structure can be used instead:
[StructLayout(LayoutKind.Explicit, Size = 8)]
private readonly struct Union
{
double @double;
}
with the use of Unsafe.BitCast<TFrom,TTo>
/Unsafe.As<TFrom,TTo>
for access.
Reference types can use a single object
.
Currently all generated extension methods are public
regardless of the visibility of the variant type.
Thus the following generates invalid code because the generated extensions have inconsistent accessibility:
namespace Foo
{
internal class A { }
[dotVariant.Variant]
public partial class Variant
{
static partial void VariantOf(A a);
}
}
// generated code:
public static class VariantEx
{
// CS0051 and CS0057: Inconsistent accessibility
public static void Match(this Variant v, out A a) { ... }
}
If System.Collections.Generic.IAsyncEnumerable<>
exists generate extension methods similar to those for IEnumerable
.
Right now disposing is only handled for IDisposable
. However if a type implements IAsyncDisposable
the variant should implement that as well and delegate asynchronous disposing to the live value where appropriate.
If a variant class
has no default constructor and all other constructors initialize the _variant
field to a non-default value then the variant cannot be empty. Under these circumstances the "empty" case is impossible to achieve and can be removed from the interface as these code paths will never execute.
Possible conflict: if constructors are later changed and the empty state becomes possible the previously safe methods could now throw InvalidOperationException
. Maybe keeping the empty state is the safer option as it reminds the user of this eventuality. This needs investigating.
Hello Miro Knejp, I dont know if you have had a look at another .Net Language that actually has discriminated union types or know that there is a language that already supports it. It is I guess not as efficient as your version but it is supported at language level. Utilizing the interoperability of F# and C# there are ways to use them from C# but it is quite cumbersome. This is just FYI and not really an Issue.
I have following Pattern
[Variant]
public class Parent<TInput, TOutput, TValue, TExternalValue>
{
static partial void VariantOf(
Notification<string> notification,
Parent<TInput, TOutput, TValue, TExternalValue>.ChildA a,
Parent<TInput, TOutput, TValue, TExternalValue>.ChildB b
);
[Variant]
public partial class ChildA
{
static partial void VariantOf(
string name,
TInput input,
TExternalValue value
);
}
[Variant]
public partial class ChildB
{
static partial void VariantOf(
TOutput output,
TValue value,
Action action
);
}
}
I get now a build issue that ChildAEx can not Build because it don't know about TExternalValue
If the user already defines certain special methods (like ToString
or Equals
) don't generate them.
This is currently only supported for Dispose
.
Candidates:
ToString()
Equals()
and GetHashCode()
Users then need to refer to the private _variant
field to get the necessary information to implement these.
Right now variant classes are only supported at namespace-level. Attempting to create one as a nested class will generate invalid code.
Currently the generated static class
containing extension methods is either public
or internal
based on the visibility of the variant itself, but it doesn't take into consideration the visibility of the value types.
In addition to that, now that we support generic types we can end up in a scenario like the following:
public partial class Variant<T1> { /* ... */ }
internal partial class Variant<T2, T2> { /* ... */ }
// generated code:
internal static class VariantEx
{
// Extension methods for Variant<T1> are public
...
// Extension methods for Variant<T1, T2> are public
...
}
Even though this is a very questionable design, users can write code like that and it should not generate a broken implementation.
To support this properly we need to determine the visibility for the extension class itself separately from the visibility of the generated extension methods. So in the above example VariantEx
should be public
with the extension methods for Variant<T1>
generated public
and for Variant<T1, T2>
generated internal
.
Hi,
Is it currently possible to create a variant with a generic parameter? e.g.
[Variant]
public partial struct Result<T>
{
static partial void VariantOf(T success, string[] errors);
}
Currently I'm getting the following error when I try:
Generator 'SourceGenerator' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type 'ArgumentException' with message 'The hintName contains an invalid character '<' at position 22. (Parameter 'hintName')'
Thanks.
Currently all generated methods are public
regardless of the visibility of the contained type.
Thus the following generates invalid code because the generated members have inconsistent accessibility:
internal class A { }
[Variant]
public class Variant
{
static partial void VariantOf(A a);
// generated code:
// CS0051 and CS0057: Inconsistent accessibility
public void Match(out A a) { ... }
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.