You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Allow type parameters to be declared co/contra variant on classes.Β #171
Currently type parameters can be declared co/contra variant on either an interface or a delegate. I propose adding support for classes.
The rules would remain the same, any in T cannot appear as any method return type nor on gettable properties. Any out T cannot appear as a parameter or on settable properties. My main motivation for this is really around things like Task<T> where I sometimes want to collect Task<Dog>, Task<Cat>, Task<Fish> into a collection of IEnumerable<Task<Pet>> and whenAlll/whenAny and only inspect their pet based result.
It cannot be legal on structs as the assignment would be a copy operation.
If it wasn't allowed, then I think that significantly limits the usefulness of the feature. For example, I don't know how would you implement Task<T> under such restrictions.
Presumably it would be legal to declare private fields of co/contra variant generics. The static method you described could not be declared as T is an out parameter and therefore can not appear as an input.
I'm not sure it would be feasible... there were good reasons to limit variance to interfaces and delegates in C# 4 (although I admit I don't remember exactly what they were). I agree that the Task<T> issue is annoying, but a better solution for this would have been to make Task<T> an interface rather than a class... well, I guess it's too late for that now (or is it?)
Yeah if TPL used an ITask<T> this probably wouldn't have been such a large issue. I'd be curious as to what insight let to to limiting variance to just delegates and intefaces.
@svick and @mburbea , so if I understand correct, Task can be implemented with something like:
class Task<out T>
{
private readonly TaskResultAccessor<T> resultAccessor;
private T Result { return resultAccessor.Value;}
}
class TaskResultAccessor<T>
{
internal T value;
public static void SetValue(TaskResultAccessor<T> accesor, T value)
{
accesor.value = value;
}
}
So we split Task and result storage into to classes: immutable covarint Task and non-variant result storage.
But it gives us not much more than using interfaces for it.
This would be a large undertaking including required CLR support, for marginal gain in language expressiveness. We don't think this is where we want to invest.
I see recently how people hype the usage of Result/Either for the flow control instead of exceptions. And for these types covariance is definitely a win. Yet nobody asks to reconsider this feature request.
Either people just ignore the pain, or they never actually used the advertised approach extensively. =)
At the end of the day, variance is a compile time construct on the jvm. At runtime, nothing exists and you can get runtime exceptions if you violate safety.
@CyrusNajmabadi So we need the runtime to be able to prove safety. I have no clue how expensive it is for the runtime team to do it. I guess it would be easier if CLR had fair readonly/immutable fields.
Yup. At the runtime level, variant interfaces and delegates are entirely safe. We'd need the same for classes. It's much more difficult though due to fields.
Activity
svick commentedon Jan 30, 2015
How would this work with accessibility? For example, could
out Ttype have a non-public field of typeT(just likeTask<T>does currently)?If that were allowed, how would you make sure the following couldn't happen?
If it wasn't allowed, then I think that significantly limits the usefulness of the feature. For example, I don't know how would you implement
Task<T>under such restrictions.mburbea commentedon Jan 30, 2015
Presumably it would be legal to declare private fields of co/contra variant generics. The static method you described could not be declared as
Tis an out parameter and therefore can not appear as an input.thomaslevesque commentedon Feb 7, 2015
I'm not sure it would be feasible... there were good reasons to limit variance to interfaces and delegates in C# 4 (although I admit I don't remember exactly what they were). I agree that the
Task<T>issue is annoying, but a better solution for this would have been to makeTask<T>an interface rather than a class... well, I guess it's too late for that now (or is it?)mburbea commentedon Feb 7, 2015
Yeah if TPL used an
ITask<T>this probably wouldn't have been such a large issue. I'd be curious as to what insight let to to limiting variance to just delegates and intefaces.thomaslevesque commentedon Feb 7, 2015
@mburbea see this answer by Eric Lippert: http://stackoverflow.com/a/2734070/98713
iskiselev commentedon Feb 18, 2015
@svick and @mburbea , so if I understand correct, Task can be implemented with something like:
So we split Task and result storage into to classes: immutable covarint Task and non-variant result storage.
But it gives us not much more than using interfaces for it.
gafter commentedon Aug 15, 2016
This would be a large undertaking including required CLR support, for marginal gain in language expressiveness. We don't think this is where we want to invest.
voroninp commentedon Oct 29, 2024
I see recently how people hype the usage of
Result/Eitherfor the flow control instead of exceptions. And for these types covariance is definitely a win. Yet nobody asks to reconsider this feature request.Either people just ignore the pain, or they never actually used the advertised approach extensively. =)
CyrusNajmabadi commentedon Oct 29, 2024
It's not that we haven't reconsidered it, it's that we don't know how to provide it.
How would this actually work? The types people mention as wanting support for don't necessarily even work variantly.
voroninp commentedon Oct 29, 2024
@CyrusNajmabadi , covariance is mostly useful for monadic types.
But how does Scala compiler ensure the correct variance for the arguments of the class then?
CyrusNajmabadi commentedon Oct 29, 2024
At the end of the day, variance is a compile time construct on the jvm. At runtime, nothing exists and you can get runtime exceptions if you violate safety.
voroninp commentedon Oct 29, 2024
@CyrusNajmabadi So we need the runtime to be able to prove safety. I have no clue how expensive it is for the runtime team to do it. I guess it would be easier if CLR had fair readonly/immutable fields.
CyrusNajmabadi commentedon Oct 29, 2024
Yup. At the runtime level, variant interfaces and delegates are entirely safe. We'd need the same for classes. It's much more difficult though due to fields.
voroninp commentedon Oct 29, 2024
@CyrusNajmabadi I'm curious whether JIT will unlock a whole new set of optimisations for strictly immutable fields.;-)
I guess it could be useful for the new Object Stack allocation feature introduced in .NET 9
Merge pull request dotnet#171 from sharwell/api-scan
Bump Nerdbank.GitVersioning from 3.5.107 to 3.5.108 (dotnet#171)