-
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]: Self Constraint #5413
Comments
I would say the second option is better, |
It would be useful to me to have this on classes, too. |
The best way this could be done is to allow it on classes and make it an associated type to prevent pollution of type parameters at the user side |
Another thing I just noticed in my own work, imagine a builder class like below: class Base<TSelf> where TSelf : Base<TSelf>
{
public TSelf SetOption()
{
...
return this; // right now this is an error
return (TSelf)this; // this has to be done
}
}
// can we make it work like below?
class Base<TSelf> where TSelf : this
{
public TSelf SetOption()
{
...
return this; // works
}
} |
Great proposal. Tiny suggestion: It might be nice if we could reference a self-type in implementing type declarations without having to re-state the type name explicitly. E.g.
becomes
That might improve code readability & brevity (I'd think most class names are >4 characters long) a fair bit. |
@fabianoliver |
"This" seemed like a natural fit if the proposal also uses it as a qualifier for the self generic type (i.e. IBuilder<this TSelf>), in which case we have precedent for "this" referring to a type indeed. It would seem like a natural fit in this case (and also would avoid adding extra keywords to the language). Having said that, personally I wouldn't be too hung about about the specific terminology, another reserved identifier would be fine as well |
I've been thinking about self-types quite a bit recently, and tl;dr, I don't think this is how we should do them. I think that self-types are better expressed in a framework of associated types (aka existential types #5556, #1328, aka abstract types, aka virtual types) or similar, primarily for the reason that @0x0737 mentions above: not polluting a type with extra type parameters. However, it is possible that we can come up with a notion of "self-constraint" that would apply orthogonally to both type parameters (now) and associated types (if we ever get them), so we may not have to wait for that. If we did such a self-type/self-constraint feature (on top of current generics and/or future associated types) we would want it to be expressive across the language - in classes as well as interfaces. And we would want examples like @TahirAhmadov's above to work, i.e., class Base<TSelf> where TSelf : this
{
public TSelf SetOption()
{
...
return this; // works
}
} It's possible that we can come up with such a proposal, but this isn't it. I worry about adopting a notion of self-types that only serves a relative corner scenario (static virtual members, which don't even have a |
This was discussed in LDM: https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-03-28.md#type-hole-in-static-abstracts While we reject this version of the self constraint, that's not to say we're uninterested in self types in general, we just think it should be an existential type, not a constraint on a visible type parameter. |
An enthusiastic +1 for this concept. Static abstract interfaces is a (somewhat) useful waypoint on the path to TSelf. C# is too great of a language not to solve CRTP! |
A self-type constraint works for broader scenarios, but it seems to me that it could be introduced implicitly as an associate type with a new type kind. eg That said, there's a few questions for the stopgap attribute proposal (#6000):
Mentioned the last point because I think |
|
@Qiu233 It's a temporary solution |
(machine translation) Bar<Derive> bar = new Derive();
bar.FooMethod();//This should be valid
Foo foo = bar ;//This should be valid
class Foo
{
public void FooMethod() { }
}
interface Bar<T> where T :this, Foo
{
}
class Derive :Foo, Bar<Derive>
{
} |
Yes, that's an excellent example of the type of thing that needs more thought before we have a |
I just came across another place where this would be useful, it would be cool to have things like below: public delegate void TypedEventHandler<TSender, TArgs>(TSender sender, TArgs args);
abstract class Base<TSelf> where TSelf : this // or "self" or w/e syntax we choose
{
public event TypedEventHandler<TSelf, EventArgs>? SomeEvent;
}
class Child : Base<Child>
{
}
var child = new Child();
child.SomeEvent += child_SomeEvent;
void child_SomeEvent(Child sender, EventArgs e) { ... } I also realized we may have a problem: class GrandChild : Child
{
}
var grandChild = new GrandChild();
grandChild.SomeEvent += grandChild_SomeEvent; // this wouldn't work, would it?
void grandChild_SomeEvent(GrandChild sender, EventArgs e) { ... } |
Would there be an issue with doing the Rust thing of having Taking TahirAhmadov's example:
*Oops, totally missed where this was suggested above. |
If it was going to use a keyword like that why not just use Either way, I don't think the syntax is the problem there. What would that actually compile to in IL? How would it be consumed? |
For years I wish this feature to be available, I hope one day will do. I do always implement all kind of unpleasant workarounds. For me it is one of the most important features that I would like to see it available into C#. |
Can we use Self Constraint to write this? public class Delegate
{
public virtual T[] GetInvocationList(); where T : this
} |
You'd need to declare |
Oh, yes, I forgot. As you can see, this method requires us to manually filter out the corresponding types. |
Self constraint for generic type parameters
Design meetings
https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-11-10.md
https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-03-28.md#type-hole-in-static-abstracts
The text was updated successfully, but these errors were encountered: