OneOf
OneOf copied to clipboard
add new method WithType to add types to a OneOf
In order that functions that return OneOf can call other functions that return
OneOf, the .WithType() method allows you to return existing OneOf structs but
with added types.
Note: Unfortunately because of the extended assembly design, OneOf types with
over 8 parameters cannot use .WithType.
public OneOf<string, double> ParseDouble(string input) {
if (double.TryParse(input, out var result)) {
return result;
} else {
return input;
}
}
public OneOf<string, double, DateTime, int> ParseDoubleOrUTCDateOrInt(string input) {
if (DateTime.TryParseExact(input, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal, out var dateResult)) {
return dateResult;
}
else if (int.TryParse(input, out var intResult)) {
return intResult;
} else {
return ParseDouble(input).WithType<DateTime>().WithType<int>();
}
}
resolves #150
Hi, thanks for using OneOf enough enough to extend it.
I think this feature would be better off in an external package, rather than in the main project, which I'm trying to keep lean.
I can add a section to the readme with a link if you create your own project.
On Mon, 28 Oct 2024, 22:07 Martin Zarate, @.***> wrote:
@.**** commented on this pull request.
In Generator/Program.cs https://github.com/mcintyre321/OneOf/pull/171#discussion_r1819813672:
@@ -49,13 +50,13 @@ namespace OneOf readonly int _index;
{IfStruct( // constructor
$@"OneOf(int index, {RangeJoined(", ", j => $"T{j} value{j} = default")})
$@"internal OneOf(int index, {RangeJoined(", ", j => $"T{j} value{j} = default")})Because it's necessary. If you look in WithType, it uses the constructor of OneOfTN+1. This is also why WithType doesn't work with large size OneOfs - it can't access the constructors of the next size beyond extendedSizeLimit
- 1 because those classes are located in a different assembly.
In Generator/Program.cs https://github.com/mcintyre321/OneOf/pull/171#discussion_r1819808627:
@@ -77,6 +78,12 @@ namespace OneOf
public int Index => _index;
{((i < extendedSizeLimit - 1) ?// can go up to the limit before extended because OneOfT8 cannot see OneOfT9$@"public OneOf<{genericArg}, TNew> WithType<TNew>() =>I see what you mean - so in your case you're using this as a convenience object to construct a new object with a new WithType and its own value, and we're just going to throw out the old value-content.
That makes sense. I'd have to see how that works with the existing methods of OneOf. Is there some equivalent "use an existing object for a convenience-object for constructing a new one" thing to build off of?
In Generator/Program.cs https://github.com/mcintyre321/OneOf/pull/171#discussion_r1819825907:
@@ -77,6 +78,12 @@ namespace OneOf
public int Index => _index;
{((i < extendedSizeLimit - 1) ?// can go up to the limit before extended because OneOfT8 cannot see OneOfT9$@"public OneOf<{genericArg}, TNew> WithType<TNew>() =>Thinking it over, maybe I should be redoing this as .WithTN+1 so that it becomes something like
OneOf<T1, T2, T3> myOneOf = SomeFunc();return myOneOf.WithT4<SomeClass>();
Then the case you describe could be done as a .FromTN+1; so OneOfT3 would have a .FromT4 for cases where you want to expand a T3 by one.
Or maybe just call that .FromNewType, which would make sense as a counterpart to .WithType, althought I don't know how much the .FromTN things get used.
In Generator/Program.cs https://github.com/mcintyre321/OneOf/pull/171#discussion_r1819833311:
@@ -77,6 +78,12 @@ namespace OneOf
public int Index => _index;
{((i < extendedSizeLimit - 1) ?// can go up to the limit before extended because OneOfT8 cannot see OneOfT9$@"public OneOf<{genericArg}, TNew> WithType<TNew>() =>I'm being silly, you can't call a static method from an instance so I think the only time you could ever use .FromTN+1 would be after literally defining var myOneOf = OneOf<T1, T2, T3>.FromT4<T4>(someValue). Why would you ever do that?
— Reply to this email directly, view it on GitHub https://github.com/mcintyre321/OneOf/pull/171#discussion_r1819813672, or unsubscribe https://github.com/notifications/unsubscribe-auth/AACDJ6UFWXYIUMBI4LYZU5LZ52YSNAVCNFSM6AAAAABQYAN6COVHI2DSMVQWIX3LMV43YUDVNRWFEZLROVSXG5CSMV3GSZLXHMZDIMBQGMYDAMZXGQ . You are receiving this because you are subscribed to this thread.Message ID: @.***>
Hi, thanks for using OneOf enough enough to extend it. I think this feature would be better off in an external package, rather than in the main project, which I'm trying to keep lean. I can add a section to the readme with a link if you create your own project.
The issue is functionality like this requires the use a private (made internal with this PR), what is your reason behind trying to keep it lean. Functionality like this PR are more syntactic sugar.
@mcintyre321
Hi, thanks for using OneOf enough enough to extend it. I think this feature would be better off in an external package, rather than in the main project, which I'm trying to keep lean. I can add a section to the readme with a link if you create your own project.
I mean it's possible but the API that makes WithType pretty slick to implement and also pretty performant is private. Without a public constructor OneOf<T0...TN>(int index, T0 value0, ... TN valueN) it becomes much less practical. Are there other forms of this you might be interested in? I might play with the reverse approach... allowing "smaller" one-ofs have an implicit cast to "larger" one-ofs as a way to implement the same feature.
@mcintyre321
I've added an alternate typecast-based approach here:
https://github.com/mcintyre321/OneOf/pull/185