- Allow ObsoleteAttribute on property accessors
- More Default Interface Member questions
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.
Example:
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.
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.
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.
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.