csharplang/meetings/2019/LDM-2019-02-27.md

145 lines
4.3 KiB
Markdown
Raw Normal View History

2019-02-28 22:57:58 +01:00
2019-03-11 08:56:43 +01:00
# C# Language Design Meeting for Feb. 27, 2019
2019-02-28 22:57:58 +01:00
## Agenda
1. Allow ObsoleteAttribute on property accessors
2. More Default Interface Member questions
## Discussion
### Allow ObsoleteAttribute on property accessors
ObsoleteAttribute, ConditionalAttribute, and CLSCompliantAttribute are
currently disallowed on property accessors. VB allows the first three, but
provides a warning for `ClSCompliant`.
The question is whether or not to loosen this restriction.
Allowing `Conditional` seems very dangerous because the "arguments" to the
method are not evaluated if the condition is false. Logically, this would
imply that the right-hand side in a property assignment expression is not
evaluated, but this seems very likely to lead to bugs and confusion.
We don't see a reason to disallow `Obsolete` or `Deprecated`, and don't
particularly care about `CLSCompliant`.
**Conclusion**
Allow the change for `Obsolete` and `Deprecated`. Leave everything else
as-is.
### Collision of lookup rules and decisions for `base()`
Example:
```C#
interface I1
{
void M(int) { }
}
interface I2
{
void M(short) { }
}
interface I3
{
override void I1.M(int) { }
}
interface I4 : I3
{
void M2()
{
base(I3).M(0) // What does this do?
}
}
```
The tricky part here is that both `M(short)` and `M(int)` are applicable to
`M(0)`, but lookup rules also say that if we find an applicable member in a
more derived interface, we ignore members from the less derived interfaces.
Combined with the rule that overrides are not found during lookup, when
looking in `I3` the first thing we find is `I2.M`, which is applicable,
meaning that `I1.M` does not appear in the list of applicable members.
Since we concluded in the previous meeting that an implementation
*must* exist in the target type, and `I2.M` is the only applicable
member, the call `base(I3).M(0)` as written is an error, because `I2.M` does
not have an implementation in `I3`.
**Conclusion**
The decision from the previous meeting is affirmed and we conclude that the
lookup rules will not be changed. It's not clear what the new lookup rules
would be and it would be difficult to find when to apply them. In general,
we think having a single set of lookup rules will reduce confusion in an
already complicated feature area.
### Semantics of `base(T).Member`
We also affirm that for `base(T).Member`:
* `T` can be a class or interface
* All members are available on `base(T).Member` including fields
* A definition or implementation must exist in `T`
*Aside: The compiler will never emit a call to a member in metadata
that is inaccessible.*
This decision essentially falls out of existing binding rules for the given
expression.
### Accessibility in interfaces
We previously agreed to support at least `protected`, `private`, and `public`.
What about `internal`, `protected internal`, or `private protected`?
In addition, what is the meaning of `protected`?
**Conclusion**
Allow all accessibility. `protected` specifically seems useful for compatibility
with other languages which allow it, and to allow interfaces to create helper
methods for their derived implementations.
There are seem to be two possible definitions of `protected`: `protected`
members are visible only in deriving interfaces, or `protected` members are
visible in both deriving interfaces and implementing classes.
The preferred definition is `protected` members being visible in all deriving
interfaces and implementing classes.
### Accessibility of overriding interface members
There are two issues here: what is the language rule around calling
overriding implementations via `base` and how to implement that rule via
accessibility in the CLR.
We like the rule that you should always be able to call an overriding
implementation through `base()` as long as you can see the definition.
The problem is that the obvious implementation (copying the accessibility of
the definition) doesn't quite work with `InternalsVisibleTo` (which is
technically not described in the language).
Proposal 1:
If the implementing member is in the same assembly as the
definition we can copy the accessibility.
Proposal 2:
For all explicit interface implementations, emit the `protected`
accessibility.
**Conclusion**
The language rule is confirmed.
We think Proposal 2 works with the language rules, is simple, and doesn't
expose anything that we would regret. Let's go with that.