Add meeting notes for April 1st, 2019
This commit is contained in:
parent
aa6f4ff72c
commit
34e86a1702
140
meetings/2019/LDM-2019-04-01.md
Normal file
140
meetings/2019/LDM-2019-04-01.md
Normal file
|
@ -0,0 +1,140 @@
|
|||
|
||||
# C# Language Design Notes for April 1st, 2019
|
||||
|
||||
## Agenda
|
||||
|
||||
1. Pattern-based Index/Range translation
|
||||
|
||||
2. Default interface implementations: Is object.MemberwiseClone() accessible in
|
||||
an interface?
|
||||
|
||||
## Discussion
|
||||
|
||||
### Index and Range patterns
|
||||
|
||||
The current design for Index has a high implementation overhead for
|
||||
types that currently have `int` indexers and all of the implementations
|
||||
sum to delegation to the `int` indexer. Also, full support can only be
|
||||
added by type authors because there are no "extension indexers" in the
|
||||
language. There's also a small overhead for using the Index type, as
|
||||
opposed to doing a "direct" translation into the `int` indexer.
|
||||
|
||||
Range is similar to the previous.
|
||||
|
||||
Proposal: contextual conversions for Index and Range members
|
||||
|
||||
In short, there would be a new contextual language-defined conversion
|
||||
from `Index` to `int` for any instance member where the receiver is
|
||||
"indexable".
|
||||
|
||||
One significant limitation is the conversion could be more applicable than
|
||||
expected, meaning that a member could be called with an Index that takes an
|
||||
int, but the member does not intend to be called with an Index, e.g. a member
|
||||
that takes a length, not a index, could be called with a System.Index type
|
||||
due to the containing type being "indexable".
|
||||
|
||||
The "contextual" conversion also seems very complicated, especially
|
||||
given that C# is already very complicated.
|
||||
|
||||
*Q: Why only support extensions only up to the type already being
|
||||
*"indexable"? Could we add support for an extension Count() or similar?*
|
||||
|
||||
**A**: Adding general collection functionality is broader than just a different form
|
||||
of indexing. That seems like an instance of a more general problem in C#.
|
||||
There are other proposals, like roles, that provide the general purpose
|
||||
extensibility needed for the above.
|
||||
|
||||
*Q: What if Count is implemented slowly or improperly?*
|
||||
|
||||
**A**: This is a violation of the framework design guidelines. Count should
|
||||
be cheap and O(1). We're willing to double down on this guideline.
|
||||
|
||||
**Range**
|
||||
|
||||
Note: the Slice method is preferred to the Range indexer if the Slice is
|
||||
present.
|
||||
|
||||
This does violate the general principle we have that exact type matches are
|
||||
always preferred over anything else and it makes adding a Slice method a
|
||||
breaking library change, since it will be preferred over the Index indexer.
|
||||
It would also allow a library to add an extension Slice to override the type's
|
||||
implementation, which is generally not desired.
|
||||
|
||||
The general argument of recognizing Slice seems useful and allows people to
|
||||
add extension support for slicing, which we like.
|
||||
|
||||
Note: multi-dimensional arrays are not supported for either
|
||||
|
||||
#### Alternative Proposal
|
||||
|
||||
We like the general approach of the prior proposal, but think adding contextual
|
||||
conversions is a step too far. Contextual conversions would be both difficult
|
||||
for the implementation and for the user to understand.
|
||||
|
||||
For Index, if a type is "indexable" (has a Count or Length, and an indexer
|
||||
that takes an `int`) then a synthetic indexer will be added to the type that
|
||||
takes an Index and implements a translation to the indexer.
|
||||
|
||||
For Range, we do the same thing, but for "rangeable types". A type is
|
||||
"rangeable" if it has a Count or a Length, and a Slice(int,int) method.
|
||||
|
||||
*Q: Is the 'indexable' pattern based on the constructed type or the original
|
||||
definition?*
|
||||
|
||||
Unknown, revisit later.
|
||||
|
||||
*Q: Do we want to support Slice(Range) or Slice(int)?*
|
||||
|
||||
Probably not -- not worth the complexity.
|
||||
|
||||
Note: for the counter-proposal, the length should only be evaluated once, and
|
||||
after the arguments are evaluated.
|
||||
|
||||
Warning or error for writing your own Range indexer?
|
||||
|
||||
**Conclusion**
|
||||
|
||||
We think the first proposal went too far, but think the alternative is workable.
|
||||
Let's try to flesh out more of the details of that proposal and then consider it
|
||||
again for inclusion in C# 8.
|
||||
|
||||
|
||||
### Revisit `object.MemberwiseClone()`
|
||||
|
||||
There are two things we'd like to consider: potential uses for the feature
|
||||
and consistency with the rest of the language rules.
|
||||
|
||||
Example of use case:
|
||||
|
||||
```C#
|
||||
interface IPoint
|
||||
{
|
||||
public int X { get; protected set;}
|
||||
public int Y { get; protected set;}
|
||||
|
||||
public IPoint WithX(int x)
|
||||
{
|
||||
var tmp = MemberwiseClone();
|
||||
tmp.X = x;
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
One argument also levelled against the feature is that it may be unexpected
|
||||
that an interface could call MemberwiseClone(). A counter argument is that it
|
||||
may be unexpected if a base class calls MemberwiseClone, but that is the
|
||||
current behavior in classes.
|
||||
|
||||
On the other hand, many people may have an impression that interfaces and
|
||||
class are essentially different type hierarchies and they meet at the
|
||||
implementation. There is also another protected member, the destructor, which
|
||||
is on object and is questionable to provide to the interface itself.
|
||||
|
||||
**Conclusion**
|
||||
|
||||
The only thing we strongly agree upon is that many of the members of object
|
||||
should not have been there in the first place. Beyond that, we aren't
|
||||
particularly swayed by either the advantages of having the access or the
|
||||
dangers of misuse. We'll slightly prefer our earlier decision: protected
|
||||
members of object are not accessible in interfaces.
|
|
@ -46,9 +46,6 @@
|
|||
- `??=` with `Nullable<T>` LHS and `T` (underlying VT) RHS (Fred)
|
||||
|
||||
See also https://github.com/dotnet/csharplang/issues/34#issuecomment-444699550 and discussion following
|
||||
|
||||
## Apr 1, 2019
|
||||
|
||||
### Index/Range Feature
|
||||
|
||||
- Pattern-based index/range translation (Jared, Stephen)
|
||||
|
@ -63,6 +60,16 @@
|
|||
|
||||
Overview of meetings and agendas for 2019
|
||||
|
||||
## Apr 1, 2019
|
||||
|
||||
[C# Design Review Notes for Apr 1, 2019](LDM-2019-04-01.md)
|
||||
|
||||
1. Pattern-based Index/Range translation
|
||||
|
||||
2. Default interface implementations: Is object.MemberwiseClone() accessible in
|
||||
an interface?
|
||||
|
||||
|
||||
## Mar 27, 2019
|
||||
|
||||
[C# Design Review Notes for Mar 27, 2019](LDM-2019-03-27.md)
|
||||
|
|
Loading…
Reference in a new issue