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

4.3 KiB

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:

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 gotoing 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.