Skip to content

Commit c85ebc3

Browse files
RexJaeschkeBillWagnerjnm2jskeetNigel-Ecma
authored
Adding support for default interface function members (#681)
* Allow interfaces as well * support default interface function members * support default interface function members * Update classes.md * Update interfaces.md * Update interfaces.md * add annotation to new examples * first pass at fixing references * find link errors part 2 * word converter warnings Enclosing a paragraph in brackets breaks the word converter. It looks for a link. * minor tweaks * Fix editorial nits * fix link * fix link * Move interface descriptions to interfaces. Some of the descriptions of interface members were in the class clause. Move them to the interface clause. Also, instead of adding a link from classes to interfaces and structs into each sub-clause, provide one blanket statement at the beginning of classes.md. * Apply suggestions from code review Co-authored-by: Joseph Musser <[email protected]> * edit pass on interfaces Clean up the interfaces markdown file * Rewrite most specific implementation rule This reads more consistently to me. Also, disallow reabstraction of interface methods in class types. * lint issues * Apply suggestions from code review Co-authored-by: Jon Skeet <[email protected]> * Respond to previous meeting feedback Make all edits except grammar changes. * fix grammar and test issues Remove interface indexer grammar (it's the same as class grammar). Fix test issues (typo `constant` => `Constant` * final pass at comments * Apply suggestions from code review Co-authored-by: Nigel-Ecma <[email protected]> * review comments, plus some noodling I need to clean up the notes from lines 578-587 to proper normative language. * Add normative rules for interface member resolution Finalize the normative language for resolution of members defined in an interface. * first set of post-meeting updates. * respond to review feedback. * Clarify more on access to interface members Clarify the rules on overriding interface members with implementations, and on accessing members with an implementation in an interface. * Apply suggestions from code review Co-authored-by: Joseph Musser <[email protected]> * update anchor * update xrefs * more anchor cleanup * Update grammar tests for DIM * mostly grammar edits Edit files other than interfaces post meeting * Updates from review at 9/25 meeting Updates terminology from 'override' to 'implementation' for interface members, clarifies rules for hiding and explicitly implementing inherited members, and improves examples and notes for interface member access and inheritance. Adds details about the use of the 'new' modifier and compiler warnings, and refines explanations of most specific implementation in diamond inheritance scenarios. * lint * Address review comments Address review comments from Nigel on 9/25-26 * Apply suggestions from code review Co-authored-by: Joseph Musser <[email protected]> * Edits per review Respond to edits except for the rabbit hole opened by https://github.com/dotnet/csharpstandard/pull/681/files#r2386725345 * fix test * fix build issue. * Update rules for lookup and mapping Update rules for interface member lookup and mapping (or implementing) an interface member. Add C# 10 note For our future selves. * Apply suggestions from code review Co-authored-by: Jon Skeet <[email protected]> * Apply suggestions from code review * Apply suggestions from code review Co-authored-by: Nigel-Ecma <[email protected]> * Apply suggestions from code review --------- Co-authored-by: Bill Wagner <[email protected]> Co-authored-by: Joseph Musser <[email protected]> Co-authored-by: Jon Skeet <[email protected]> Co-authored-by: Nigel-Ecma <[email protected]>
1 parent b79db0e commit c85ebc3

File tree

9 files changed

+1546
-1254
lines changed

9 files changed

+1546
-1254
lines changed

standard/basic-concepts.md

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ There are several different types of declaration spaces, as described in the fol
7878
- Within all compilation units of a program, *namespace_member_declaration*s with no enclosing *namespace_declaration* are members of a single combined declaration space called the ***global declaration space***.
7979
- Within all compilation units of a program, *namespace_member_declaration*s within *namespace_declaration*s that have the same fully qualified namespace name are members of a single combined declaration space.
8080
- Each *compilation_unit* and *namespace_body* has an ***alias declaration space***. Each *extern_alias_directive* and *using_alias_directive* of the *compilation_unit* or *namespace_body* contributes a member to the alias declaration space ([§14.5.2](namespaces.md#1452-using-alias-directives)).
81-
- Each non-partial class, struct, or interface declaration creates a new declaration space. Each partial class, struct, or interface declaration contributes to a declaration space shared by all matching parts in the same program ([§16.2.4](structs.md#1624-partial-modifier)). Names are introduced into this declaration space through *class_member_declaration*s, *struct_member_declaration*s, *interface_member_declaration*s, or *type_parameter*s. Except for overloaded instance constructor declarations and static constructor declarations, a class or struct cannot contain a member declaration with the same name as the class or struct. A class, struct, or interface permits the declaration of overloaded methods and indexers. Furthermore, a class or struct permits the declaration of overloaded instance constructors and operators. For example, a class, struct, or interface may contain multiple method declarations with the same name, provided these method declarations differ in their signature ([§7.6](basic-concepts.md#76-signatures-and-overloading)). Note that base classes do not contribute to the declaration space of a class, and base interfaces do not contribute to the declaration space of an interface. Thus, a derived class or interface is allowed to declare a member with the same name as an inherited member. Such a member is said to ***hide*** the inherited member.
81+
- Each non-partial class, struct, or interface declaration creates a new declaration space. Each partial class, struct, or interface declaration contributes to a declaration space shared by all matching parts in the same program ([§16.2.4](structs.md#1624-partial-modifier)). Names are introduced into this declaration space through *class_member_declaration*s, *struct_member_declaration*s, *interface_member_declaration*s, or *type_parameter*s. Except for overloaded instance constructor declarations and static constructor declarations, a class, struct, or interface cannot contain a member declaration with the same name as the class, struct, or interface. A class, struct, or interface permits the declaration of overloaded methods and indexers. Furthermore, a class or struct permits the declaration of overloaded instance constructors and operators. For example, a class, struct, or interface may contain multiple method declarations with the same name, provided these method declarations differ in their signature ([§7.6](basic-concepts.md#76-signatures-and-overloading)). Note that base classes do not contribute to the declaration space of a class, and base interfaces do not contribute to the declaration space of an interface. Thus, a derived class or interface is allowed to declare a member with the same name as an inherited member. Such a member is said to ***hide*** the inherited member.
8282
- Each delegate declaration creates a new declaration space. Names are introduced into this declaration space through parameters (*fixed_parameter*s and *parameter_array*s) and *type_parameter*s.
8383
- Each enumeration declaration creates a new declaration space. Names are introduced into this declaration space through *enum_member_declarations*.
8484
- Each method declaration, property declaration, property accessor declaration, indexer declaration, indexer accessor declaration, operator declaration, instance constructor declaration, anonymous function, and local function creates a new declaration space called a ***local variable declaration space***. Names are introduced into this declaration space through parameters (*fixed_parameter*s and *parameter_array*s) and *type_parameter*s. The set accessor for a property or an indexer introduces the name `value` as a parameter. The body of the function member, anonymous function, or local function, if any, is considered to be nested within the local variable declaration space. When a local variable declaration space and a nested local variable declaration space contain elements with the same name, within the scope of the nested local name, the outer local name is hidden ([§7.7.1](basic-concepts.md#771-general)) by the nested local name.
@@ -268,7 +268,7 @@ When access to a particular member is allowed, the member is said to be ***acces
268268
The ***declared accessibility*** of a member can be one of the following:
269269
270270
- Public, which is selected by including a `public` modifier in the member declaration. The intuitive meaning of `public` isaccess not limited”.
271-
- Protected, which is selected by including a `protected` modifier in the member declaration. The intuitive meaning of `protected` isaccess limited to the containing class or types derived from the containing class”.
271+
- Protected, which is selected by including a `protected` modifier in the member declaration. The intuitive meaning of `protected` isaccess limited to the containing class or interface, or classes or interfaces derived from the containing type”.
272272
- Internal, which is selected by including an `internal` modifier in the member declaration. The intuitive meaning of `internal` isaccess limited to this assembly”.
273273
- Protected internal, which is selected by including both a `protected` and an `internal` modifier in the member declaration. The intuitive meaning of `protected internal` isaccessible within this assembly as well as types derived from the containing class”.
274274
- Private protected, which is selected by including both a `private` and a `protected` modifier in the member declaration. The intuitive meaning of `private protected` isaccessible within this assembly by the containing class and types derived from the containing class.”
@@ -402,7 +402,7 @@ As described in [§7.4](basic-concepts.md#74-members), all members of a base cla
402402
403403
### 7.5.4 Protected access
404404
405-
When a `protected` or `private protected` instance member is accessed outside the program text of the class in which it is declared, and when a `protected internal` instance member is accessed outside the program text of the program in which it is declared, the access shall take place within a class declaration that derives from the class in which it is declared. Furthermore, the access is required to take place *through* an instance of that derived class type or a class type constructed from it. This restriction prevents one derived class from accessing protected members of other derived classes, even when the members are inherited from the same base class.
405+
When a `protected` or `private protected` instance member is accessed outside the program text of the class in which it is declared, and when a `protected internal` instance member is accessed outside the program text of the program in which it is declared, the access shall take place within a class declaration that derives from the class in which it is declared. Furthermore, the access is required to take place *through* an instance of that derived class type or a class type constructed from it. This restriction prevents one derived class from accessing protected members of other derived classes, even when the members are inherited from the same base class. Instance interface members defined with `protected` or `private protected` access cannot be accessed from a `class` or `struct` that implements that interface; these can be accessed only from derived interfaces. However, `class` and `struct` types can define overridden `protected` instance members declared in an interface it implements.
406406
407407
Let `B` be a base class that declares a protected instance member `M`, and let `D` be a class that derives from `B`. Within the *class_body* of `D`, access to `M` can take one of the following forms:
408408
@@ -781,9 +781,9 @@ When a name in an inner scope hides a name in an outer scope, it hides all overl
781781
782782
Name hiding through inheritance occurs when classes or structs redeclare names that were inherited from base classes. This type of name hiding takes one of the following forms:
783783
784-
- A constant, field, property, event, or type introduced in a class or struct hides all base class members with the same name.
785-
- A method introduced in a class or struct hides all non-method base class members with the same name, and all base class methods with the same signature ([§7.6](basic-concepts.md#76-signatures-and-overloading)).
786-
- An indexer introduced in a class or struct hides all base class indexers with the same signature ([§7.6](basic-concepts.md#76-signatures-and-overloading)) .
784+
- A constant, field, property, event, or type introduced in a class, struct, or interface hides all base class members with the same name.
785+
- A method introduced in a class, struct, or interface hides all non-method base class members with the same name, and all base class methods with the same signature ([§7.6](basic-concepts.md#76-signatures-and-overloading)).
786+
- An indexer introduced in a class, struct, or interface hides all base type indexers with the same signature ([§7.6](basic-concepts.md#76-signatures-and-overloading)) .
787787
788788
The rules governing operator declarations ([§15.10](classes.md#1510-operators)) make it impossible for a derived class to declare an operator with the same signature as an operator in a base class. Thus, operators never hide one another.
789789
@@ -913,9 +913,9 @@ where:
913913
`R₀` is determined as follows:
914914

915915
- If `x` is zero and the *namespace_or_type_name* appears within a generic method declaration ([§15.6](classes.md#156-methods)) but outside the *attributes* of its *method-header*, and if that declaration includes a type parameter ([§15.2.3](classes.md#1523-type-parameters)) with name `I`, then `R₀` refers to that type parameter.
916-
- Otherwise, if the *namespace_or_type_name* appears within a type declaration, then for each instance type `T` ([§15.3.2](classes.md#1532-the-instance-type)), starting with the instance type of that type declaration and continuing with the instance type of each enclosing class or struct declaration (if any):
916+
- Otherwise, if the *namespace_or_type_name* appears within a type declaration, then for each instance type `T` ([§15.3.2](classes.md#1532-the-instance-type)), starting with the instance type of that type declaration and continuing with the instance type of each enclosing class, struct, or interface declaration (if any):
917917
- If `x` is zero and the declaration of `T` includes a type parameter with name `I`, then `R₀` refers to that type parameter.
918-
- Otherwise, if the *namespace_or_type_name* appears within the body of the type declaration, and `T` or any of its base types contain a nested accessible type having name `I` and `x` type parameters, then `R₀` refers to that type constructed with the given type arguments. If there is more than one such type, the type declared within the more derived type is selected.
918+
- Otherwise, if the *namespace_or_type_name* appears within the body of the type declaration, and `T` or any of its base types contain a nested accessible type having name `I` and `x` type parameters, then `R₀` refers to that type constructed with the given type arguments. If there is more than one such type, the type declared within the more derived type is selected. It is a compiler error if no type is more derived than all others.
919919
> *Note*: Non-type members (constants, fields, methods, properties, indexers, operators, instance constructors, finalizers, and static constructors) and type members with a different number of type parameters are ignored when determining the meaning of the *namespace_or_type_name*. *end note*
920920
- Otherwise, for each namespace `N`, starting with the namespace in which the *namespace_or_type_name* occurs, continuing with each enclosing namespace (if any), and ending with the global namespace, the following steps are evaluated until an entity is located:
921921
- If `x` is zero and `I` is the name of a namespace in `N`, then:
@@ -945,7 +945,7 @@ For each repetition `n`, where `1 ≤ n ≤ k`, its resolution, `Rₙ`; which in
945945

946946
- If `x` is zero and `Rₚ` refers to a namespace and `Rₚ` contains a nested namespace with name `I`, then `Rₙ` refers to that nested namespace.
947947
- Otherwise, if `Rₚ` refers to a namespace and `Rₚ` contains an accessible type having name `I` and `x` type parameters, then `Rₙ` refers to that type constructed with the given type arguments.
948-
- Otherwise, if `Rₚ` refers to a (possibly constructed) class or struct type and `Rₚ` or any of its base classes contain a nested accessible type having name `I` and `x` type parameters, then `Rₙ` refers to that type constructed with the given type arguments. If there is more than one such type, the type declared within the more derived type is selected.
948+
- Otherwise, if `Rₚ` refers to a (possibly constructed) class, struct, or interface type and `Rₚ` or any of its base types contain a nested accessible type having name `I` and `x` type parameters, then `Rₙ` refers to that type constructed with the given type arguments. If there is more than one such type, the type declared within the more derived type is selected. It is a compiler error if no type is more derived than all others.
949949
> *Note*: If the meaning of `T.I`, for some type `T`, is being determined as part of resolving the base class specification of `T` then the direct base class of `T` is considered to be `object` ([§15.2.4.2](classes.md#15242-base-classes)). *end note*
950950
- Otherwise, the *namespace_or_type_name* is invalid and a compile-time error occurs.
951951

@@ -956,6 +956,30 @@ A *namespace_or_type_name* is permitted to reference a static class ([§15.2.2.4
956956
- The *namespace_or_type_name* is the `T` in a *namespace_or_type_name* of the form `T.I`, or
957957
- The *namespace_or_type_name* is the `T` in a *typeof_expression* ([§12.8.18](expressions.md#12818-the-typeof-operator)) of the form `typeof(T)`
958958

959+
> *Example*:
960+
>
961+
> <!-- Example: {template:"standalone-lib-without-using", name:"MultipleNested", expectedErrors:["CS0104"]} -->
962+
> ```csharp
963+
> interface A
964+
> {
965+
> class NestedClass { public static void M() {} }
966+
> }
967+
>
968+
> interface B
969+
> {
970+
> class NestedClass { public static void M() {} }
971+
> }
972+
>
973+
> interface C : A, B
974+
> {
975+
> public void Test() { NestedClass.M(); } // ambiguity between A.NestedClass and B.NestedClass
976+
> }
977+
> ```
978+
>
979+
> In the example above, the call to `NestedClass.M()` in `C.Test()` is ambiguous between `B.NestedClass.M()` and `A.NestedClass.M()` because neither is more derived than the other. An explicit reference to either `A.NestedClass.M()` or `B.NestedClass.M()` is required to resolve the ambiguity.
980+
>
981+
> *end example*
982+
959983
### 7.8.2 Unqualified names
960984
961985
Every namespace declaration and type declaration has an ***unqualified name*** determined as follows:

0 commit comments

Comments
 (0)