-
Notifications
You must be signed in to change notification settings - Fork 92
Adding support for default interface function members #681
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
base: draft-v8
Are you sure you want to change the base?
Adding support for default interface function members #681
Conversation
Depending how PR #680 is resolved, some tweaks might be needed with this PR. As at 2025-05-03, that PR is still pending, and is tied to the review of this PR. |
84a1703
to
caba5c7
Compare
caba5c7
to
dc8d7a0
Compare
rebased on the latest draft-v8 on 09-23-2023 |
Should the references to "C# implementations targeting the CLI" be changed somehow because the ECMA standard CLI does not support default interface members? Possible answers include:
|
Re @KalleOlaviNiemitalo's concern about the Ecma CLI standard not supporting default interface function members, we previously made a related change to the draft-v8 Introduction, which in V7, said:
It now says:
I think that allows us to say nothing more for this feature with regard to the CLI. |
When an interface `IB` extends an interface `IA`, it is a compile-time error for `IA` to depend on `IB`. An interface **directly depends on** its direct base interfaces (if any) and **directly depends on** the type within which it is immediately nested (if any). | ||
Given these definitions, the complete set of types upon which a type depends is the transitive closure of the *directly depends on* relationship. |
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.
Given these definitions, the complete set of types upon which a type depends is the transitive closure of the *directly depends on* relationship. | |
Given these definitions, the complete set of types upon which a type depends is the reflexive and transitive closure of the *directly depends on* relationship. |
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 suggested change is required to disallow class A : A {}
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.
It been a long day, but does not adding reflexive require “A depends on A” not disallow it?
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.
I'll make the alternative suggestion to delete line 277. I don't think it's needed.
> | ||
> *end example* | ||
Every interface and class shall have a most specific override for every virtual member among the overrides appearing in the type or its direct and indirect interfaces. The ***most specific override*** is a unique override that is more specific than every other override. If there is no override, the member itself is considered the most specific override. |
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.
What is "an override"?
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.
I would use the term from the feature spec "most specific implementation". The feature spec defines it as
The most specific implementation is a unique implementation that is more specific than every other implementation. If there is no implementation, the member itself is considered the most specific implementation.
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.
We prefer override
here. But, we must ensure that virtual
has a correct definition for interfaces that declare virtual
members either abstract or non-abstract.
Also, consider how to use the language or classes but, "stretch" it as appropriate for interface declarations.
Define "most specific override" in the context of interface declarations.
I don't recall why this is assigned to me. Is it for general review, or to answer the question about
In short, the |
Going from memory, but I believe as a general reviewer. |
closed and reopened to get all tests to run |
@RexJaeschke and @BillWagner could you look at resolving the conflict? I'm not sure whether we can realistically expect most members to have reviewed this before the meeting later today though. (I'll see whether I can find time, but I'm prioritizing #606.) |
22549fb
to
efb69e5
Compare
@jskeet I did a full rebase. My main goal in prioritizing this for today's meeting is to get it assigned to someone for next meeting. I agree that there isn't time to get it reviewed thoroughly. |
@BillWagner Looking again, did we get as far as assigning it during the last meeting? We spent quite a bit of time talking about prose vs grammar for constraints, but we didn't record the next step... |
Enclosing a paragraph in brackets breaks the word converter. It looks for a link.
efb69e5
to
4418683
Compare
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.
We know that there's more work coming here. For this next meeting, I'd like to see the committee agree on some key points regarding the direction for this PR:
- Terms used. Neal had some earlier comments, I added more on what terms to use for the new concepts in this feature.
- The overall strategy of defining members of
class
,struct
andinterface
declarations. Right now, we mostly define everything in terms of class, then deltas for interfaces and structs. But, sometimes those deltas are in the class clause, sometimes in interfaces or structs. Over the next several releases, the differences continue to shrink (static abstract members in interfaces, struct default constructors and field initializers, and so on.) I see two potential directions:
- Continue to define interfaces and structs in terms of a delta from class types. If we follow that, I'd recommend moving all the remaining text for deltas out of the class clause into structs or interfaces (including some added in this PR)
- Create a new "Members" clause the defines the common features of members, and then classes, interfaces, and structs can reference that with deltas.
Personally, I think the former is easier because "Members" are hard to define without one of class, struct, interface. And all of class, struct, and interface are incomplete without fully specifying all the members.
/cc @jskeet @RexJaeschke for meeting agenda notes.
When an interface `IB` extends an interface `IA`, it is a compile-time error for `IA` to depend on `IB`. An interface **directly depends on** its direct base interfaces (if any) and **directly depends on** the type within which it is immediately nested (if any). | ||
Given these definitions, the complete set of types upon which a type depends is the transitive closure of the *directly depends on* relationship. |
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.
I'll make the alternative suggestion to delete line 277. I don't think it's needed.
@@ -4,7 +4,9 @@ | |||
|
|||
An interface defines a contract. A class or struct that implements an interface shall adhere to its contract. An interface may inherit from multiple base interfaces, and a class or struct may implement multiple interfaces. | |||
|
|||
Interfaces can contain methods, properties, events, and indexers. The interface itself does not provide implementations for the members that it declares. The interface merely specifies the members that shall be supplied by classes or structs that implement the interface. | |||
Interfaces may contain various kinds of members, as described in [§18.4](interfaces.md#184-interface-members). The interface itself may provide ***default implementation***s for some or all of the function members that it declares, in which case, those members are *not* part of the interface contract. For those members for which the interface does not provide default implementations, the interface merely specifies the members that shall be supplied by classes or structs that implement the interface. |
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.
I think we should remove this phrase. Any interface members that have a default implementation are part of the interface contract, but they have a default implementation:
Interfaces may contain various kinds of members, as described in [§18.4](interfaces.md#184-interface-members). The interface itself may provide ***default implementation***s for some or all of the function members that it declares, in which case, those members are *not* part of the interface contract. For those members for which the interface does not provide default implementations, the interface merely specifies the members that shall be supplied by classes or structs that implement the interface. | |
Interfaces may contain various kinds of members, as described in [§18.4](interfaces.md#184-interface-members). The interface itself may provide ***default implementation***s for some or all of the function members that it declares. For those members for which the interface does not provide default implementations, the interface merely specifies the members that shall be supplied by classes or structs that implement the interface. |
| interface_event_declaration | ||
| interface_indexer_declaration | ||
: constant_declaration | ||
| field_declaration |
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.
This is incorrect. Interface can't include non-static fields. We'll need to rework the grammar in classes.md to provide a distinction between instance and static data fields.
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.
Perhaps this could be addressed with text placing on restrictions, as may have to be the case for events which have many permutations. (https://github.com/dotnet/csharpstandard/pull/681/files#r2180552691)
| field_declaration | ||
| method_declaration | ||
| property_declaration | ||
| event_declaration |
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.
field-like events can't be declared in an interface. This will also require more splitting of the grammar rules for events to distinguish the two syntaxes for them.
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.
They may be if they are static, though. To address this through splitting of grammar rules, does that entail splitting event_declaration
into static_event_declaration
, instance_custom_event_declaration
, and instance_fieldlike_event_declaration
? Could we instead add non-grammar text which says "Event declarations in interfaces must either be static or explicitly declare accessors"?
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.
Actually, field-like events can sometimes be declared depending also on whether they are abstract or virtual/sealed.
using System;
interface I
{
// Allowed, has a static backing field.
public static event EventHandler StaticFieldlike;
// Allowed, has accessors.
public static event EventHandler StaticCustom { add { } remove { } }
// Allowed, implicitly abstract.
public event EventHandler InstanceFieldlikeAbstract;
// Disallowed, asks for an instance backing field because it is not abstract.
public virtual event EventHandler InstanceFieldlikeVirtual;
public sealed event EventHandler InstanceFieldlikeSealed;
// Disallowed: CS8712 event cannot use event accessor syntax
public abstract event EventHandler InstanceCustomAbstract { add; remove; }
// Allowed, implicitly virtual.
public event EventHandler InstanceCustomVirtual { add { } remove { } }
// Allowed, has accessors.
public sealed event EventHandler InstanceCustomSealed { add { } remove { } }
}
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.
So all event declaration syntaxes are allowed in interfaces except for the following:
- An instance event with the
virtual
orsealed
modifiers must declare accessors. - An instance event with the
abstract
modifier must not declare accessors.
; | ||
``` | ||
|
||
An interface declaration declares zero or more members. The members of an interface shall be methods, properties, events, or indexers. An interface cannot contain constants, fields, operators, instance constructors, finalizers, or types, nor can an interface contain static members of any kind. | ||
An interface declaration declares zero or more members. The members of an interface shall be constants, fields, methods, properties, events, indexers, operators, constructors, and types, some of which may be instance, others static, as described in the subclauses for each interface member kind. |
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.
This needs to clarify that interfaces can't include instance data fields (including field-like events). It might be the best place to mention that interfaces use the same syntax for auto-implemented properties for an abstract property.
@@ -242,24 +255,133 @@ If a `new` modifier is included in a declaration that doesn’t hide an inherite | |||
The set of members of an interface declared in multiple parts ([§15.2.7](classes.md#1527-partial-type-declarations)) is the union of the members declared in each part. The bodies of all parts of the interface declaration share the same declaration space ([§7.3](basic-concepts.md#73-declarations)), and the scope of each member ([§7.7](basic-concepts.md#77-scopes)) extends to the bodies of all the parts. | |||
|
|||
Consider an interface with a default implementation for a member `M`. As `M` is not part of that interface’s contract, outside that interface or any interface derived from it, that name is not visible. How then can it be accessed? The following code shows how: |
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.
Two thoughts:
- Lines 258 - 294 should probably be non-normative. The normative language should be that an interface member must be accessed as an explicit interface member.
- I don't like the phrasing about "not part of the contract". Instead, I'd suggest we phrase this in terms of "visibility" or even "inheritance". An interface member with a default implementation must be accessed through a reference of that interface type. It isn't visible as a member of an implementing class, or derived interface.
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.
Agreed. The real reason why you can't access M
directly on C
is that C
doesn't declare a public M
.
This is not really new with DIMs. It happens any time C
skips creating its own public M
to implicitly implement the interface. What allows it to skip creating a public M
is the presence of an explicit implementation somewhere. The only thing that's new with DIMs is that the explicit implementation can be in any of the interfaces as well as being in C or any of its base classes.
- A static declaration that is not extern or abstract shall have a *block* as a *method_body*. | ||
- A virtual declaration that is not extern shall have a *block* as a *method_body*. | ||
- A private declaration that is not extern shall have a *block* as a *method_body*. | ||
- A sealed declaration that is not extern shall have a *block* as a *method_body*. | ||
- An async declaration shall have a *block* as a *method_body*. |
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.
This needs some wordsmithing. I don't think we want "block" here. Expression bodied members are legal.
|
||
*method_modifier* shall not include `override`. | ||
|
||
An interface method declaration that has a *block* as a *method_body* is a default implementation ([§18.1](interfaces.md#181-general)), so it is *not* part of the interface’s contract. A *method_declaration* shall not have *type_parameter_constraints_clause*s unless it also has a *type_parameter_list*. |
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.
Two bits here:
Again, my concern with "part of the contract" as the terminology. And, an expression bodied member is legal, so block is the wrong term.
> | ||
> *end example* | ||
Every interface and class shall have a most specific override for every virtual member among the overrides appearing in the type or its direct and indirect interfaces. The ***most specific override*** is a unique override that is more specific than every other override. If there is no override, the member itself is considered the most specific override. |
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.
I would use the term from the feature spec "most specific implementation". The feature spec defines it as
The most specific implementation is a unique implementation that is more specific than every other implementation. If there is no implementation, the member itself is considered the most specific implementation.
It is a compile-time error for a class to depend on itself. For the purpose of this rule, a class ***directly depends on*** its direct base class (if any) and *directly depends on* the nearest enclosing class within which it is nested (if any). Given this definition, the complete set of classes upon which a class depends is the transitive closure of the *directly depends on* relationship. | ||
It is a compile-time error for a class to depend on itself. For the purpose of this rule, a class ***directly depends on*** its direct base class (if any) and *directly depends on* the type within which it is immediately nested (if any). | ||
|
||
When an interface `IB` extends an interface `IA`, it is a compile-time error for `IA` to depend on `IB`. An interface **directly depends on** its direct base interfaces (if any) and **directly depends on** the type within which it is immediately nested (if any). |
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.
Why are interfaces being mentioned here?
@@ -4,7 +4,9 @@ | |||
|
|||
An interface defines a contract. A class or struct that implements an interface shall adhere to its contract. An interface may inherit from multiple base interfaces, and a class or struct may implement multiple interfaces. | |||
|
|||
Interfaces can contain methods, properties, events, and indexers. The interface itself does not provide implementations for the members that it declares. The interface merely specifies the members that shall be supplied by classes or structs that implement the interface. | |||
Interfaces may contain various kinds of members, as described in [§18.4](interfaces.md#184-interface-members). The interface itself may provide ***default implementation***s for some or all of the function members that it declares, in which case, those members are *not* part of the interface contract. For those members for which the interface does not provide default implementations, the interface merely specifies the members that shall be supplied by classes or structs that implement the interface. |
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 grammar was strange and it also seemed to rule out having the implementations be supplied by another interface.
Interfaces may contain various kinds of members, as described in [§18.4](interfaces.md#184-interface-members). The interface itself may provide ***default implementation***s for some or all of the function members that it declares, in which case, those members are *not* part of the interface contract. For those members for which the interface does not provide default implementations, the interface merely specifies the members that shall be supplied by classes or structs that implement the interface. | |
Interfaces may contain various kinds of members, as described in [§18.4](interfaces.md#184-interface-members). The interface itself may provide ***default implementation***s for some or all of the function members that it declares, in which case, those members are *not* part of the interface contract. Members for which the interface does not provide default implementations are abstract. Their implementations are supplied by derived interfaces or by classes or structs which implement the interface. |
Interfaces can contain methods, properties, events, and indexers. The interface itself does not provide implementations for the members that it declares. The interface merely specifies the members that shall be supplied by classes or structs that implement the interface. | ||
Interfaces may contain various kinds of members, as described in [§18.4](interfaces.md#184-interface-members). The interface itself may provide ***default implementation***s for some or all of the function members that it declares, in which case, those members are *not* part of the interface contract. For those members for which the interface does not provide default implementations, the interface merely specifies the members that shall be supplied by classes or structs that implement the interface. | ||
|
||
> *Note*: Historically, adding a new function member to an interface impacted all existing consumers of that interface type; it was a breaking change! The addition of default interface function member implementations allowed developers to upgrade an interface while still enabling any implementors to override that implementation. Users of the interface can accept the default implementation as a non-breaking change; however, if their requirements are different, they can override the default implementations. *end note* |
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.
In C# 13, when ref structs are allowed to implement interfaces, ref structs can't make use of DIMs. Therefore in C# 13+, adding an interface member goes back to being a breaking change (but only for consumers who implement your interface on a ref struct
).
An interface declaration declares zero or more members. The members of an interface shall be methods, properties, events, or indexers. An interface cannot contain constants, fields, operators, instance constructors, finalizers, or types, nor can an interface contain static members of any kind. | ||
An interface declaration declares zero or more members. The members of an interface shall be constants, fields, methods, properties, events, indexers, operators, constructors, and types, some of which may be instance, others static, as described in the subclauses for each interface member kind. | ||
|
||
All interface members implicitly have public access; however, an explicit access modifier ([§7.5.2](basic-concepts.md#752-declared-accessibility)) is permitted. |
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.
This statement doesn't apply to static constructors which become allowed in C# 8 as part of DIMs.
|
||
An *interface_declaration* creates a new declaration space ([§7.3](basic-concepts.md#73-declarations)), and the type parameters and *interface_member_declaration*s immediately contained by the *interface_declaration* introduce new members into this declaration space. The following rules apply to *interface_member_declaration*s: | ||
|
||
- The name of a type parameter in the *variant_type_parameter_list* of an interface declaration shall differ from the names of all other type parameters in the same *variant_type_parameter_list* and shall differ from the names of all members of the interface. | ||
- The name of a method shall differ from the names of all properties and events declared in the same interface. In addition, the signature ([§7.6](basic-concepts.md#76-signatures-and-overloading)) of a method shall differ from the signatures of all other methods declared in the same interface, and two methods declared in the same interface shall not have signatures that differ solely by `in`, `out`, and `ref`. | ||
- The name of a property or event shall differ from the names of all other members declared in the same interface. | ||
- The name of a method shall differ from the names of all other kinds of function members declared in the same interface. In addition, the signature ([§7.6](basic-concepts.md#76-signatures-and-overloading)) of a method shall differ from the signatures of all other methods declared in the same interface, and two methods declared in the same interface may not have signatures that differ solely by `in`, `out`, and `ref`. |
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.
Does "function members" include classes? For instance, this does not compile:
interface I
{
void Foo();
class Foo { }
}
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.
If "function members" does include classes then this line above is incorrect because a nested class may have both the private
and sealed
modifiers:
A
private
orsealed
function member of an interface shall have a body. Aprivate
function member shall not have the modifiersealed
.
|
||
*constant_declaration* is described in [§15.4](classes.md#154-constants). | ||
|
||
As a *constant_declaration* is considered to have a default implementation ([§18.1](interfaces.md#181-general)), it is *not* part of the interface’s contract. |
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 "default impl means it's out of the contract" philosophy comes up here as well and in the following blocks. I'm not sure yet that I accept this philosophy. One could also say that the member is still in the contract. That is, the class is still "on the hook" to provide the whole contract, including this member- it's just that the class has chosen to fulfill that contract by deferring to the default implementation for this member.
With C# 13 and ref structs, this becomes clearer. Ref structs can't make use of default implementations, so they must implement every member explicitly. This shows that every interface member really is part of the interface contract, even when a default implementation exists for it.
*property_modifier* shall not include `override`. | ||
A *property_declaration* that has a *block* as an *accessor_body* is a default implementation ([§18.1](interfaces.md#181-general)), so it is *not* part of the interface’s contract. A *property_declaration* that has no default implementation is always considered part of the interface’s contract; it is *never* considered to be an automatically implemented property ([§15.7.4](classes.md#1574-automatically-implemented-properties)). |
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.
Expression-bodied properties should be considered here. int Prop => 42;
is a default implementation. Also echoing the concern about excluding DIMs from the "contract."
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.
Can we also restrict this to talking about instance properties? I get confused when I enter this paragraph with static int Prop { get; set; }
in mind, which is an auto prop.
|
||
All interface members implicitly have public access; however, an explicit access modifier ([§7.5.2](basic-concepts.md#752-declared-accessibility)) is permitted. | ||
|
||
An interface function member whose declaration includes a body is an implicitly `virtual` member unless the `sealed` or `private` modifier is used. The `virtual` modifier may be used on a function member that would otherwise be implicitly `virtual`. Similarly, although `abstract` is implied for interface function members without bodies, that modifier may be given explicitly. A non-virtual function member may be declared using the `sealed` keyword. |
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.
This only applies to instance members.
|
||
It is a compile-time error for *field_declaration* to declare an instance field. | ||
|
||
As a static *field_declaration* is considered to have a default implementation ([§18.1](interfaces.md#181-general)), it is *not* part of the interface’s contract. |
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.
Here and elsewhere: do we want to talk about fields and constants as "having implementations"? Do we even want to talk about static members as having default implementations, as though there was any "slot" being "implemented" where we selected the "default" option for the slot? There's no virtual dispatch for a static call, so this language seems forced.
(Ignoring for now that static abstract interface members come in C# 11)
> class D: B {} | ||
> class E: B {} | ||
> class C: I<D> |
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 typical style is ClassName : InterfaceName
, so I don't love this change. Elsewhere in the file, new code has been added that similarly does not follow the typical style.
interface_method_header | ||
: identifier '(' parameter_list? ')' ';' | ||
| identifier type_parameter_list '(' parameter_list? ')' | ||
type_parameter_constraints_clause* ';' | ||
; |
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.
Why retain interface_method_header
when interface_method_declaration
is removed?
|
||
The list of requirements for valid combinations of modifiers stated for a class method is extended, as follows: | ||
|
||
- A static declaration that is not extern or abstract shall have a *block* as a *method_body*. |
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 static declaration that is not extern or abstract shall have a *block* as a *method_body*. | |
- A static declaration that is not extern shall have a *block* as a *method_body*. |
Until C# 11, a static declaration cannot be abstract.
### 18.4.3 Interface properties | ||
<!-- markdownlint-enable MD028 --> | ||
> *Note*: See §interface-fields for an example that not only shows a static method with default implementation, but as that method is called `Main` and has the right return type and signature, it’s also an entry point! *end note* |
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.
There are some exclamation points being added in notes on this one 😂 Is that typical?
Interface properties are declared using *interface_property_declaration*s: | ||
A virtual method with implementation declared in an interface may be overridden to be abstract in a derived interface. This is known as ***reabstraction***. |
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.
We're flagging the term "override/overridden" in other comment threads; so, pointing it out here as well.
Re the MS proposal: The main challenge when reading it was the (misleading) occurrence of the modifier
override
in numerous examples and narrative. As best as I can tell, this modifier is not actually permitted on any interface member. Instead, overriding is achieved via explicit implementation.There is one open question, which has to do with the topic "Base Interface Invocations," for which the decision "Decided on
base(N.I1<T>).M(s)
" was made. However, as far as I can tell, support for this was not added to the V8 compiler. Can someone please confirm (or refute) that.BTW, I think the proposal is misnamed: it really applies to all interface function members (properties, indexers, and events as well), not just methods. (it also allows nested types.)
Note: No spec changes are needed to support entry point
Main
in an interface. Any non-generic type containing aMain
method withvoid
/int
return and no/onestring[]
parameter list is already permitted, which not only allowsMain
in a struct or class, but now also in an interface.As of V7, the descriptions of the various member kinds has been located in classes.md, with augmenting and/or overriding text in structs.md, with pointers from structs.md back into classes.md, and that continues. However, now that many members kinds can have implementations in interfaces as well, I've added an intro para to the start of most member sections in classes.md, which contains forward pointers to that member kind's occurrence in structs.md and interfaces.md, as appropriate.