csharplang/meetings/2018/LDM-2018-12-03.md
Nick Schonning 6cd82c21ed fix: MD033/no-inline-html
Inline HTML get swallowed in MD and HTML rendering
2019-05-25 01:31:46 -04:00

132 lines
4.3 KiB
Markdown

# C# LDM notes for Dec 3, 2018
## Agenda
1. `using` declaration open issues
2. 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:
```C#
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:
1. Add indexers that return the same types (string returns a string, array returns
an array, Span returns a Span, etc.)
2. Don't add indexers that allocate/copy, add overloads to do slicing with ranges
3. Add indexers that return Span\<T>
4. Add indexers that return Memory\<T>
5. 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:
1. 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.
2. 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.