-
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
Add description of extension interface implementation #7928
base: main
Are you sure you want to change the base?
Conversation
There are a lot of unknowns and difficult semantic constraints with bringing extension interface implementation to C#. This documents many of the challenges and outlines some of the most desirable semantics. When a particular semantic is suggested, example code is provided to show why that semantic is valuable.
Fix formatting
string M2<T>(T p) where T : IPrettyPrint { ... } | ||
``` | ||
Unlike in the Interface parameter example, no conversion is performed. However, in the above example, both `string` and `int` should be considered valid substitutions for the type parameter `T`, even though they would not have originally satisfied the `IPrettyPrint` constraint. Once again, the interface members on `IPrettyPrint` should be invocable on `p` and they should use the implementation provided in the extension implementations. | ||
The main differences in this example and Interface parameter are around boxing. While a value type would have been copied and boxed with an `IPrettyPrint` parameter type, a generic substitution would normally not box the parameter during the invocation of `M2` or during a call to `PrettyPrint` if the input argument directly implemented `IPrettyPrint`. The same should be true of an extension implementation, and side-effects of `M2` and `PrettyPrint` should be propagated back to the `i` parameter in the call `M2(i)`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same should be true of an extension implementation, and side-effects of
M2
andPrettyPrint
should be propagated back to thei
parameter in the callM2(i)
.
I don't understand this.
In today's C#, a value type is copied in a method call, even in a generic one.
What do you mean by: should be propagated back to the i
parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On a constrained instance invocation on a generic type parameter, the receiver is a ref
variable, so the interface invocation is side-effect-preserving.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a constrained instance invocation on a generic type parameter
Can you give an example please, I'm still not sure to fully understand this line :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, so if you have a call like
interface IFace {
void Mutate();
}
struct S : IFace {
public int F;
public void Mutate() {
F++;
}
}
void M<T>(T t) where T : IFace {
Console.WriteLine(t.F);
t.Mutate();
Console.WriteLine(t.F);
}
You can see that the call to the interface Method Mutate
does not copy the struct t
. Instead, the function mutates the struct variable directly. If you look underneath, you'll see the reason why is that the this
parameter in the S.Mutate
method is actually ref S this
, that is it's passing the struct by-ref.
This is a very high-level explanation. The exact semantics and requirements of the feature will be detailed below. | ||
|
||
## Why | ||
The basic idea and inspiration traces back to Wadler’s paper [1] on a feature called “type classes.” The basic goal of the feature is to allow the description of arbitrary sets of functions (interfaces) and arbitrary implementations of those sets (interface implementations). C# already allows some of those features, but the current design has severe limitations in two areas: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should there be a link to the paper [1]
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, endnotes got lost somehow. It's https://dl.acm.org/doi/pdf/10.1145/75277.75283
### Interface Parameter | ||
|
||
First, let’s consider one of the simplest possible examples: extending an existing primitive type with a new interface, and passing an instance of this type to a parameter of the interface type. | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(applies to other code snippets below)
``` | |
```C# |
Add reference to paper
There are a lot of unknowns and difficult semantic constraints with bringing extension interface implementation to C#. This documents many of the challenges and outlines some of the most desirable semantics. When a particular semantic is suggested, example code is provided to show why that semantic is valuable.