-
Notifications
You must be signed in to change notification settings - Fork 49
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
[MVUX] Better support for nullability annotations #1605
Comments
@dr1rrb is this something we can get done in 5.1? If so, can you update the release number |
About "factories", adding a // Confusion possible between cases 3 and 7
var int1 = Feed.Async(_ => default(int)); // => Some(0)
var int2 = Feed.Async(_ => 42); // => Some(42)
var int3 = Feed.Async(_ => default(int?)); // ==> None // currently: Some(null)
var int4 = Feed.Async(_ => 42); // => Some(42)
var int5 = Feed<int>.Async(_ => default(int)); // => Some(0)
var int6 = Feed<int>.Async(_ => 42); // => Some(42)
var int7 = Feed<int?>.Async(_ => default(int?)); // => Some(null)
var int8 = Feed<int?>.Async(_ => 42); // => Some(42)
// Confusion possible between cases 3 and 7
var struct1 = Feed.Async(_ => default(MyStruct)); // => Some(0)
var struct2 = Feed.Async(_ => new MyStruct(42)); // => Some(42)
var struct3 = Feed.Async(_ => default(MyStruct?)); // ==> None // currently: Some(null)
var struct4 = Feed.Async(_ => new MyStruct(42)); // => Some(42)
var struct5 = Feed<MyStruct>.Async(_ => default(MyStruct)); // => Some(0)
var struct6 = Feed<MyStruct>.Async(_ => new MyStruct(42)); // => Some(42)
var struct7 = Feed<MyStruct?>.Async(_ => default(MyStruct?)); // => Some(null)
var struct8 = Feed<MyStruct?>.Async(_ => new MyStruct(42)); // => Some(42)
// Confusion possible between cases 1,3 and 7
var str1 = Feed.Async(_ => default(string)); // => None // currently: Some(null)
var str2 = Feed.Async(_ => "42"); // => Some("42")
var str3 = Feed.Async(_ => default(string?)); // => None // currently: Some(null)
var str4 = Feed.Async(_ => "42"); // => Some("42")
// var str5 = Feed<string>.Async(_ => default(string)); // compilation issue
var str6 = Feed<string>.Async(_ => "42"); // => Some("42")
var str7 = Feed<string?>.Async(_ => default(string?)); // => Some(null)
var str8 = Feed<string?>.Async(_ => "42"); // => Some("42")
// Confusion possible between cases 1,3 and 7
var obj1 = Feed.Async(_ => default(MyObject)); // => None // currently: Some(null)
var obj2 = Feed.Async(_ => new MyObject(42)); // => Some(42)
var obj3 = Feed.Async(_ => default(MyObject?)); // => None // currently: Some(null)
var obj4 = Feed.Async(_ => new MyObject(42)); // => Some(42)
// var obj5 = Feed<MyObject>.Async(_ => default(MyObject)); // compilation issue
var obj6 = Feed<MyObject>.Async(_ => new MyObject(42)); // => Some(42)
var obj7 = Feed<MyObject?>.Async(_ => default(MyObject?)); // => Some(null)
var obj8 = Feed<MyObject?>.Async(_ => new MyObject(42)); // => Some(42) Proposed changedThe common issue is with the case 7, so we propose to change the current behavior also in it to return a
NoteFeed of value-types are usually only used for binding purposes where anyway |
When we look at "operators", we have 2 cases to consider:
Case 1 could be named "None as null", while case 2 is "null as None". ProposalTo match the "new behavior" suggested for "factories", we should also follow the "null as None". This means that we should constraint the "return type" on all operators to In order to allow users to return However we should NOT implement the "None as null", this is to avoid to implicitly convert Special cases of imperative operatorsCurrently State.UpdateInput and output types are the same, implementing the "null as None" somehow forces us to also implement the "None as null". This is not as problematic as for We suggest to keep it as-is (i.e. both "None as null" and "null as None") State.ForEachSame here, this is designed to execute imperative code, converting None to default is somehow the expected behavior. We should however add an We suggest to keep it as-is (i.e. both "None as null") and add Feed.GetAwaiterSame here, this is designed to execute imperative code, converting None to default is somehow the expected behavior. User can already do We suggest to keep it as-is (i.e. both "None as null") and add ExamplesIState<int> intState = null!;
await intState.Update(v => v + 1); // Dangerous case: user will get 0 in case of None
await intState.Update(i => default(int?));
var intValue = await intState; // int // Dangerous case: user will get 0 in case of None
IState<MyStruct> structState = null!;
await structState.Update(v => v with { Value = 43 }); // Dangerous case: user will get default(MyStruct) in case of None
await structState.Update(v => default(MyStruct?));
var structValue = await structState; // default(MyStruct) // Dangerous case: user will get default(MyStruct) in case of None
IState<string> strState = null!;
await strState.Update(v => (v ?? "").ToString());
await strState.Update(v => default(string?));
var strValue = await strState; // string?
IState<MyObject> objectState = null!;
await objectState.Update(v => (v ?? new(42)) with { Value = 43 });
await objectState.Update(v => default(MyObject?));
var objectValue = await objectState; //MyObject? |
To summarized the suggested changes:
|
What would you like to be added:
Feed.Async<T>
whereT : notnull
should accept anAsyncFunc<T?>
and automatically interpret anull
asNone
.Same for other operators like
.Select
, and.SelectAsync
.Why is this needed:
The language now have the nullable annotations which are commonly used by devs. Doing such would improve user experience and help to use the
None
state which is often not used.For which Platform:
Anything else we need to know?
Option<T>
should be hidden from "first level public API" (could be usable only with "advanced" operators)State.Update
The text was updated successfully, but these errors were encountered: