Replies: 3 comments 14 replies
-
That has never been allowed in C#:
This feature proposal came specifically from the discussions around shapes and it was identified as one of the runtime changes necessary to make shapes possible. |
Beta Was this translation helpful? Give feedback.
-
An example showing a valid C# to generate TypeLoadException when executing: public interface I
{
static abstract void M();
}
public class C : I
{
public static void M()
{
}
}
//C1<I> is invalid, because it calls I.M(), which does not exist. However, we can create a C1<I> as below.
public class C1<T> where T : I
{
public void E()
{
T.M();
}
}
//Two storage classes that stores the invalid interface implementation.
public class GenericStorage<T1>
{
public static IExecuteInvalid E;
public interface IExecuteInvalid
{
void Execute<T2>() where T2 : T1;
}
}
public class NongenericStorage : GenericStorage<I>
{
private class CExecuteInvalid : IExecuteInvalid
{
public void Execute<T2>() where T2 : I
{
var x = new C1<T2>();
x.E();
}
}
public static void Set()
{
E = new CExecuteInvalid();
}
}
//Helper class to access GenericStorage<I>.E.Execute<I>.
public sealed class C3<T>
{
public static void M()
{
GenericStorage<T>.E.Execute<T>();
}
}
public class Program
{
static void Main()
{
//Create an implementation that bypasses generic check.
NongenericStorage.Set();
//Call GenericStorage<I>.E.Execute<I>, which calls C1<I>.E().
C3<I>.M();
}
} |
Beta Was this translation helpful? Give feedback.
-
There's a lot of interesting feedback here that we'll be sure to look at. Remember, though, that abstract statics in interfaces is in preview in .NET 6. We absolutely can make breaking changes in the design and implementation of the feature before it ships in a supported fashion. So there's no dire "stop the presses you're making a terrible mistake" problem here. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
There has been discussed under the original proposal for static abstract members #4436, but I feel it's probably better to start a new discussion specifically on its impact on the language and whether it would be good for C#.
Unexpected behaviors with static virtual members
The problem is mainly from the assumption that everything "implementing" the interface must have all its static abstract members available. However, this assumption is too breaking, because it is not compatible with many existing concepts in C# (and of many similar OOP programming languages). Specifically:
1. It breaks the symmetry among interfaces (with and without static abstract members).
Interfaces with at least one static abstract members will become different. When an interface does not contain such members, it is not affected by this proposal and behaves as expected, but once it contains one, the following bullet points illustrate the strange behaviors it will have.
2. Abstract class is no longer allowed to leave members as abstract.
This is allowed:but this is not allowed:
but this is not allowed:
It also breaks the symmetry between static and non-static members.
3. It breaks the assumption that
T
is allowed atT2
inM<T2> where T2 : T
.This is allowed:
This is not allowed:
This is quite annoying as we usually think the
where T : I
means "whereT
is anI
". But here C# tells us thatI
is not anI
. This is a violation of reflexive property of equality. Generics should be orthogonal to interface, and it does not make sense for generics to be affected by a new feature added for interface.4. It allows variables of unconstructible type.
This is similar to an example I gave in the thread of the original proposal.
Here in
C3.M()
, we can access the fieldX
from base class, but we cannot use the type of this field anywhere.Other reasons
1. Irreversible change.
The above assumption that all static abstract members from
I
will have an implementation inT
givenwhere T : I
will be an irreversible change. Once we allow codes with this assumption to compile, reversing it (e.g., by adding aconcrete
constraint) will be a breaking change. C# has been careful in not having much breaking changes, so impact of this feature seems unlikely to be solvable ever in the future.2. Existing difficulties to extend.
There are problems related to default implementation and abstract members in classes, as mentioned in the original proposal. It is unclear how they will be solved, and even whether they can ever be solved. It seems impossible to me that the default implementation will ever be possible on static abstract members under the current design.
3. Covered by Shape.
Discussion on this feature seems to start in Feb this year, with less than half-year time to design and implement. There are great proposals here in this repo like shape that has been designed for many years, and it can fully cover this proposal without having these problems. Yes it is much more difficult and cannot be added to the language soon, but we have been waiting for many years, I think it is OK for us to wait for a few more.
There are also many other great proposals in this repo that have been closed simply because they are covered by shape. It is unfair that discussions on those features are closed so quickly without much thinking, while this one, also covered by shape and with all the problems mentioned above, to be implemented first.
Beta Was this translation helpful? Give feedback.
All reactions