-
Notifications
You must be signed in to change notification settings - Fork 1k
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
[Proposal]: Task<T>
nullability covariance
#3950
Comments
Is there a general proposal for this? That is, any operation that takes a If I supply a non-nullable object as a nullable parameter, it works just fine, but when I supply a generic of a nullable as a generic of a non-nullable, it gives me a warning. It isn't null forgiveness that I need, but the opposite--non-null forgiveness, which I thought should be implicit and not really a conscious thing that we would have to do. |
@szalapski I don't think that's true, for the same reason that any operation that takes a Let's say something expects a var list = new List<string>();
DoSomething(list); // This should, and does, cause a warning; you can't pass `List<string>` as `List<string?>`
Console.WriteLine(list[0].Length); // Or this happens
void DoSomething(List<string?> list) => list.Add(null); |
You are right. Thinking it through, I intuitively expected that the |
You use the nullability warning suppression operator, which is postfix DoSomething(list!); It's called the https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-forgiving operator, but I'm calling it the null-blindness operator and hoping it catches on. :D |
It isn't null forgiveness that I need, but the opposite--non-null forgiveness, which I thought should be implicit and not really a conscious thing that we would have to do. |
Nevertheless, the operator is a nullability warning suppression operator and is the way intended for you to suppress this particular nullability warning. |
The nullability improvements working group discussed this issue on 24th October. Here are the notes: https://github.com/dotnet/csharplang/blob/main/meetings/working-groups/nullability-improvements/NI-2022-10-24.md. |
Would that be limited to nullability only? There's a discussion on that as a general type inference feature: #92 which is what Java does already. |
But why limit it to only nullability covariance? Making |
That's very interesting. Apologies that I missed these comments when they were originally made. I'll try and take a look at this discussion when I can. |
I think the reason is we feel better about breaking the rules if the feature is limited to just nullability. The result field in a Task is mutable, so on the "language-theoretical" level it's not safe to make it covariant. There might be some kind of guardrail you can insert which makes it "likely enough" that the requirements around safe covariant conversions won't be violated, but it's not clear. |
It's probably too late now, but what are the downsides of creating and using something like I think option 1 is best. Yes, it introduces a certain amount of work, but I think it brings enough benefits to justify it. Option 0 has a smell to it - now the compiler has to remember a list of types, meh - and option 2 doesn't really work for |
The working group notes talk about the idea of |
I can't see how the immutable collections could use variance. They are not purely covariant. For example: https://learn.microsoft.com/en-us/dotnet/api/system.collections.immutable.immutablelist-1.add?view=net-7.0#system-collections-immutable-immutablelist-1-add(-0) An ImmutableList of strings is not one of objects. You would not be able to add an object to the actual instance, despite the type implying it was possible. |
I'm proposing that |
Interesting concept :-). I could envision something like that being possible. |
In addition to what @sab39 wrote. other types don't have such a limitation, for example, |
This sounds like something interesting, but it seems to touch on full covariance on types, rather than nullable covariance which is purely compiler-sugar but currently a friction point. One solution for the issue about nullability and Concretely, like the OP says, this produces an warning: public Task<string?> GetAsync() => Task.FromResult(""); But an attribute could be placed on public static Task<T> FromResult<[NullableCovariant] T>(T value); The effect here would be that at callsites of this method, if the inferred type argument is a (non-nullable) reference type and the output is target typed to the nullable version of the type argument, the compiler is allowed to lift the inferred type argument to the nullable version. |
I'd rather have the attribute on the type parameter of using System.Threading.Tasks;
static class C {
static void M(out Task<string?> task) {
N(out task);
}
static void N(out Task<string> task) {
task = Task.FromResult("");
}
} even though I suppose it's quite easy to suppress warnings by adding |
Yeah, I was thinking about as a separate and longer term idea. Should I start a discussion to propose it as such? |
Come to think of it, the Task<object> FooAsync()
{
return Task.FromResult(""); // currently this is an error, but it would be helpful if it worked
}
Task<objecct> BarAsync()
{
return Task.FromResult(0); // to make this work, it would be outside of the scope of regular covariance,
// but would be cool nonetheless
// if we go with the "target-typing" approach, and not the covariance approach, this should work fine
} |
Anything new here? Got my self in this situation, not only with Have a method and cant make an overload for this because string is a reference type and those types are identical: My hacky workaround would be something like
This should really be fixed because it affects all generic types and their usage as parameters..... //EDIT: To clarify more: I dont want those two overloads, but right now i cant express to the compiler, that i want a function that takes //EDIT2: //EDIT3: //EDIT4: |
Task<T>
nullability covarianceSummary
Task<T>
nullability covariance (LDM tentatively approved, needs design proposal for task-like types)It should be possible to return a
Task<string!>
for aTask<string?>
.Motivation
See some examples of this problem: dotnet/roslyn#40759, dotnet/roslyn#40757
Unresolved questions
Design meetings
Split issue from #3868
https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-09-28.md#nullability-improvements
https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-09-06.md#taskt-nullability-covariance
The text was updated successfully, but these errors were encountered: