4.3 KiB
C# LDM notes for Dec 3, 2018
Agenda
using
declaration open issues- Return type of
Range
indexer on array and FX types
Discussion
using
declaration open issues
Q: Do we want to reserve '_' to mean discard in a using
e.g., using var _ *= ...;
?
This would let the user set the scope for an expression without creating an
identifier.
Conclusion
Yes, this seems useful.
Deconstruction
Q: Do we want to allow a deconstruction in the declaration e.g., using var (x, y) = GetResources()
?
We noted that this could mean two different things: the outer tuple is disposed, then deconstructed, or the elements are deconstructed, then each is disposed.
Conclusion
This seems too complicated for the marginal benefit. Rejected.
goto
and using declarations
Example:
goto label;
using var x = ...;
label:
...
Can you goto
past a using
declaration? Can you goto
before a using
declaration? Can you goto
in the same block, but not past the using
? Can
you even have labels and using var
in the same block?
Conclusion
You definitely can't goto
"past" a using var. That would be similar to
jumping "into" a try-finally.
We could allow jumping "out" of a using var
, but we're concerned it may
be confusing, since there may not be a syntactical indication that the
disposal is executed.
When goto
ing a label in the same statement list as a using var
, the
goto
must not have a using var
syntactically between the goto
and
the label.
Extension Dispose()
and Nullable<T>
Q: Should an extension Dispose()
method be called if the receiver is null?
No, the behavior is defined as item?.Dispose()
, and so Dispose()
will not
be called for null
values.
Q: For a value of type S?
and extension methods Dispose(this S? s)
and
Dispose(this S s)
, which is called?
Same resolution as above: the behavior is defined as value?.Dispose()
, so
we do the same thing as item?.Dispose()
(which picks Dispose(this S s)
).
Return values of Range indexers
Proposals:
- Add indexers that return the same types (string returns a string, array returns an array, Span returns a Span, etc.)
- Don't add indexers that allocate/copy, add overloads to do slicing with ranges
- Add indexers that return Span
- Add indexers that return Memory
- Do nothing
(3) and (2) are initially attractive because they automatically produce the fastest possible behavior with no allocation. Essentially, users are in a pit of success from a performance perspective.
There are two main problems with this:
- Span is not considered "general purpose" and can be quite difficult to use. Not being able to store the value in a field or convert it to an interface is difficult.
- Span and Memory are very new types and most code doesn't use them. Users
would often be forced to coerce into another type anyway. This is particularly
bad for strings, where almost all operations are only available on the
string
type.
The opposing proposal is (1). The theory is that users are more likely to be able use that they pass in. For many users, the additional allocation and copying will not be prohibitive. For performance sensitive users, instead of passing arrays around directly, they can proactively convert to Span or Memory and all subsequent indexing operations will be 0-allocation.
The main problem with (1) is performance-sensitive users are essentially in a pit of failure in this proposal. The short syntax makes the indexers attractive, but likely to harm performance.
It was also noted that indexers are generally not supposed to hide expensive or complicated operations, according to .NET coding guidelines. However, Range indexers are fundamentally new operations (they even return a different type -- a collection instead of an element) and it's not clear we should naively apply the same standards for existing indexers to Range indexers.
Conclusion
Settled on (1), with overloads for AsSpan(Range r)
that return a Span<T>
.
This should reduce the work necessary to go directly from a Span-compatible
types to Span slices.
CoreFX Proposal: https://github.com/dotnet/designs/pull/48
Q: Do we want to allow Range/Index indexers on multidimensional arrays? They are currently prohibited.
Conclusion
Undecided. We need to discuss this in another LDM.