-
Notifications
You must be signed in to change notification settings - Fork 90
Add Support for Indexers and Ranges #605
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: draft-v8
Are you sure you want to change the base?
Changes from all commits
369ca4f
d77d147
1f97b8e
c3047be
3813628
54c4a55
56e0322
1ef3ab2
c051a5d
8ba0cfa
18319e5
7cb2cd5
3233609
d699f4f
0b81b47
a007699
8895e78
d8b297d
53d51fd
12b4632
f62b30f
cf03cbd
9e74541
5157c57
39a0fdd
7c67270
fb5703c
3981944
7d53e7b
5b596d0
d1a8fec
faf2eac
0b88e74
b2873d8
cca7304
cd2a008
1877160
be2d311
dd7764e
f651978
16818f0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -3299,6 +3299,8 @@ In a *ref_property_body* an expression body consisting of `=>` followed by `ref` | |||||||||||||||||||||
|
||||||||||||||||||||||
When a property declaration includes an `extern` modifier, the property is said to be an ***external property***. Because an external property declaration provides no actual implementation, each of the *accessor_body*s in its *accessor_declarations* shall be a semicolon. | ||||||||||||||||||||||
|
||||||||||||||||||||||
A type is ***countable*** if it has an instance property named `Length` or `Count` with an accessible `get` accessor ([§15.7.3]( classes.md#1573-accessors)) and a return type of `int`. | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmmm…
A single plank is countable (in the sense intended)? Maybe:
Suggested change
with a x-ref to wherever collection gets defined (see #1250). Note: Qualifying, “collection type”, also avoids integers not be countable – which could otherwise confuse the numerate 😉 Note: This doesn’t address “In case both There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While having general terms is good this particular term currently only exists to be referenced in the new clauses “Implicit Index support” and ”Range Index support”. It would be better to move this to down to those two clauses, possibly even removing it as defined term altogether. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's move this to the general clause of indexable sequences, where we're introducing other terms that are only relevant to that. (This doesn't address the plank example, but at least suggests where countable types are relevant.) |
||||||||||||||||||||||
|
||||||||||||||||||||||
### 15.7.2 Static and instance properties | ||||||||||||||||||||||
|
||||||||||||||||||||||
When a property declaration includes a `static` modifier, the property is said to be a ***static property***. When no `static` modifier is present, the property is said to be an ***instance property***. | ||||||||||||||||||||||
|
@@ -5542,3 +5544,129 @@ When the body of the async function terminates, the return task is moved out of | |||||||||||||||||||||
If the return type of the async function is `void`, evaluation differs from the above in the following way: Because no task is returned, the function instead communicates completion and exceptions to the current thread’s ***synchronization context***. The exact definition of synchronization context is implementation-dependent, but is a representation of “where” the current thread is running. The synchronization context is notified when evaluation of a `void`-returning async function commences, completes successfully, or causes an uncaught exception to be thrown. | ||||||||||||||||||||||
|
||||||||||||||||||||||
This allows the context to keep track of how many `void`-returning async functions are running under it, and to decide how to propagate exceptions coming out of them. | ||||||||||||||||||||||
|
||||||||||||||||||||||
## §indexable-sequence Indexable sequences | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This clause & its subclauses might be better after §15.9 Indexers, or as a subclause of §15.9. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Punt on this until the rest is ready. |
||||||||||||||||||||||
|
||||||||||||||||||||||
### §indexable-sequence-general General | ||||||||||||||||||||||
|
||||||||||||||||||||||
An ***indexable sequence*** is an ordered set of zero or more elements having the same type. Any given element can be accessed via an index, and a contiguous subset of elements—referred to as a ***slice***—can be denoted via a range. | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ref: #1250 a Proposal to Define Some Container-Related Terms I think this definition of indexable sequence (or collection) is not right. #1250 has a renaming and different definition:
#1250 also defines collection:
I”m not sure where the “polymorphic” in the collection definition comes from, but it does correctly drop the “same type” of indexable sequence. The term “ordered set” allows the reading that it is the elements that are ordered (as in [partially] ordered sets and
Maybe:
Suggested change
Or something like that… This is similar to the definition in #1250, but without the underlying definition of collection (for now…). The definition of range here doesn’t address that a C# So there is a disparity between the term “range” and C#’s type There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd suggest either "sequence" or "collection" instead of "set" as well. Likewise "subsequence" instead of "subset"? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Replacement comment, I hit add too quickly] @jskeet dropping set is a good idea. But are we taking about sequences, which by (English language) definition are ordered, or collections which are not? Do we need to make it clear that any ordering here comes from the index type being ordered, not the elements? Indices do not need to be ordered per se, but a range of indices implies ordered indices, and indexable sequence/collection is being defined to be used by ranges. Which gives us:
Suggested change
Too detailed/convoluted? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question under discussion: does There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting types:
We may want to limit this to integer-based indexes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We also had some discussion about what "ordered index" means (especially when |
||||||||||||||||||||||
|
||||||||||||||||||||||
An index is represented by a read-only variable of the value type `System.Index`. A range is represented by a read-only variable of value type `System.Range`, which contains a start and end index. A slice of an array is represented by a (possibly empty) array. The representation of a slice of a user-defined type is determined by the implementer of that type. | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm. Should this be a countable type?
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does a slice have to be of a countable type? You can write an uncountable type with an indexer accepting a range, and make it fail at execution time if either end of the range is "from the end". I agree it will usually be of a countable type, just trying to explore... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jskeet – In C# terms a slice made from a Looking at your query made me think how careful we have to be with terms here.
No, an indexer takes an index as its argument, which does not need to be of type I think we might yet need a lot of careful wordsmithing. Drat! |
||||||||||||||||||||||
|
||||||||||||||||||||||
For an indexable sequence of length *N*, elements can be accessed using indexes 0 through *N-1*, which are relative to the start. Elements can also be accessed relative to the end via the `^` index-from-end operator (§index-from-end-operator). `^0` denotes the (non-existent) element just beyond the end. | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could specify here the range of valid values that may be provided with the Also, nit:
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jnm2 – 0 through N for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The definition of indexable sequence, both original and revised versions, do not fix the type of the index. Here the type is fixed to being an integer number (it does not state the actual type). |
||||||||||||||||||||||
|
||||||||||||||||||||||
A slice can be obtained using the `..` range operator (§range-operator). A range of the form `s..e` starts at element `s` and ends with the element immediately prior to element `e`. | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could mention here that either or both ends may be omitted, each referring then to its appropriate extremity within the available range. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's fine as is. The other forms of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, a slice might be obtained using a range – or it might fail, a range can be constructed using the range operator… TBD: Wordsmith a suggestion There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The TBD from the preceding comment:
Suggested change
|
||||||||||||||||||||||
|
||||||||||||||||||||||
All single-dimensional and jagged arrays ([§17.1](arrays.md#171-general)) are indexable sequences; multi-dimensional arrays are not! The use of indexes and ranges with arrays is described in [§12.8.11.2](expressions.md#128112-array-access). | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it typical in the spec to mention jagged arrays as though they were separate from single-dimensional arrays? I had thought of jagged arrays as a special case of single-dimensional arrays. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I might consider it a note:
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with @jnm2 here – C# doesn’t have jagged arrays per se, it supports single-dimensional arrays where the element type can be an array which:
I would just drop the reference (and the
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "All single-dimensional are indexable sequences" - this needs to be "All single-dimensional arrays are indexable sequences" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Array access is now 12.8.12.2:
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we also say that these arrays are countable as well? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jskeet – I’ve now added that to the suggested definition of slice. |
||||||||||||||||||||||
|
||||||||||||||||||||||
An object of type `string` is an indexable sequence. | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And countable? (I won't keep adding this...) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jskeet – Once we’ve the definition of indexable narrowed down to what is needed for this feature then countability (if it still exists as a concept) will be implied as using an |
||||||||||||||||||||||
|
||||||||||||||||||||||
A user-defined type can provide explicit support for indexer access ([§12.8.11.3](expressions.md#128113-indexer-access)) using `System.Index` and `System.Range`. (See §indexable-sequence-expl-support-for-index and §indexable-sequence-expl-support-for-range.) If various criteria are met, an existing user-defined type that does *not* have such explicit support, shall have provided for it by the implementation implicit support for such indexer and range access. (See §indexable-sequence-impl-support-for-index and §indexable-sequence-impl-support-for-range.) In both cases, the type is recognized as being an indexable sequence type. | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One sentence felt hard for me to follow. Does this version achieve the same goals you're looking to achieve?
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like Joseph's wording here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For convenience updating @jnm2’s suggestion with @BillWagner x-ref update:
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. indexer access moved:
Suggested change
|
||||||||||||||||||||||
|
||||||||||||||||||||||
### §indexable-sequence-support-for-index Providing support for Index | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For both this section and the corresponding ranges section, I propose we rework them to introduce a pattern based description, following the format used for The concept is that a countable sequence has a certain pattern for indexer, Count, Length, etc. A type can provide support for ranges and index operations by implementing a pattern: Indexer that takes Finally, for arrays and other types the compiler recognizes as countable, the compiler can synthesize the lowering of the indexer operations. |
||||||||||||||||||||||
|
||||||||||||||||||||||
#### §indexable-sequence-expl-support-for-index Explicit Index support | ||||||||||||||||||||||
|
||||||||||||||||||||||
A type having an instance indexer taking a single argument of type `System.Index`, or a first argument of that type followed by optional arguments, may be indexed as described by [§12.8.11.3](expressions.md#128113-indexer-access). | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I may be off on a tangent here, and I'm happy to get a better understanding of what the aims are in this sentence, but here goes 😁 If optional arguments are mentioned, is Also, the Roslyn compiler is happy with this code, which does not have an argument of type using System;
var expr = new C();
_ = expr[^2];
_ = expr is [];
class C
{
public object this[params Index[] x] => throw null;
public int Count => throw null;
} In addition, due to implicit conversions, the type need not be using System;
var expr = new C();
_ = expr[^2];
_ = expr is [];
class C
{
public object this[params CustomIndex[] x] => throw null;
public int Count => throw null;
}
class CustomIndex
{
public static implicit operator CustomIndex(Index i) => throw null;
} The compiler is also happy with the indexer having a We also didn't mention refness of the parameter ( I've observed the compiler team defining this general concept in terms of being able to bind arguments to an applicable overload. If we defined things the same way in the spec somewhere, we could refer to that definition. Thereby maybe we could sidestep all the gotchas around repeating ourselves exhaustively, as to what allows binding to succeed for these features. There are other instances below to which this would also apply. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could the change be this simple:
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Tangents are welcome! A core part of the task is looking into all the nooks’n’crannies that might not be covered in the source material.
How an indexer access is resolved to a particular indexer is already covered in §12.8.11.3 Indexer access which in turn relies on §12.6.4 Overload resolution – between them these cover such things as optional parameters, So rather specifying indexers that have an argument of type Suggested rewording:
Suggested change
Once the para is reduced to this it is clear it is stating the blindly obvious – before Following below there may be further suggestions changing “take” to ”accept”/”apply” – this and those need to be accepted/rejected as a whole. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Aside from anything else: I think these should refer to parameters, not arguments. There's no such thing as an optional argument, only an optional parameter. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jskeet – I think the use of “argument” is correct in my suggestion? |
||||||||||||||||||||||
|
||||||||||||||||||||||
> *Example*: In [§15.9](classes.md#159-indexers), there is an example defining type `BitArray`, which stores bits in an array of `int`. Individual bits are accessed for read/write via an `int` indexer. Adding an `Index` indexer that simply interprets the `Index` argument as an `int`, is simple: | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Given that the preceding para has, hopefully, just stated the obvious – that adding another indexer is nothing new, I question whether this really needs an example which visually separates the previous para from the next clause that builds upon it. However I accept this might not be a universal view! 😉 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If nothing else, we can reduce the clutter using expression bodies: partial class BitArray
{
public bool this[Index idx]
{
get => this[idx.GetOffset(Length)]; // use the [int] indexer
set => this[idx.GetOffset(Length)] = value; // use the [int] indexer
}
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jskeet – that’s an improvement 👍 |
||||||||||||||||||||||
> | ||||||||||||||||||||||
> <!-- Example: {template:"standalone-console", name:"ExplicitIndexSupport", additionalFiles:["BitArrayPartial1.cs"], expectedOutput:["ba1[0] = True", "ba1[98] = False", "ba1[Index 0] = True", "ba1[^1] = True"]} --> | ||||||||||||||||||||||
> ```csharp | ||||||||||||||||||||||
> partial class BitArray | ||||||||||||||||||||||
> { | ||||||||||||||||||||||
> public bool this[Index idx] | ||||||||||||||||||||||
> { | ||||||||||||||||||||||
> get | ||||||||||||||||||||||
> { | ||||||||||||||||||||||
> return this[idx.GetOffset(Length)]; // use the [int] indexer | ||||||||||||||||||||||
> } | ||||||||||||||||||||||
> set | ||||||||||||||||||||||
> { | ||||||||||||||||||||||
> this[idx.GetOffset(Length)] = value; // use the [int] indexer | ||||||||||||||||||||||
> } | ||||||||||||||||||||||
> } | ||||||||||||||||||||||
> } | ||||||||||||||||||||||
> ``` | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> *end example* | ||||||||||||||||||||||
|
||||||||||||||||||||||
#### §indexable-sequence-impl-support-for-index Implicit Index support | ||||||||||||||||||||||
|
||||||||||||||||||||||
An implementation shall behave as if it provides a non-virtual instance indexer member with a single parameter of type `System.Index` for any type that meets the following criteria: | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could be clarified. The implementation only behaves this way in regard to the call site which calls this synthesized indexer. It does not, for instance, behave as if it provides this indexer within the class definition itself when the class is being compiled: Console.WriteLine(typeof(C).GetProperties().Length); // 2
class C
{
public int this[int index] { get => throw null; set => throw null; }
public int Count => throw null;
} Same again below. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jnm2 – Hmm, I read “shall behave as if it provides” (emphasis added) as clearly stating what you’d like clarified – but folk do read things differently. Can you suggest some wording? BTW I would expect that an implementation could choose to add an actual indexer to the type should it wish and be compliant, so if folk agree and don’t think this wording allows that then some wordsmithing will be required. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd personally not expect it to add an actual indexer to the type, as that could then be detected as a breaking change later if someone adds an actual indexer with a different parameter name. But I do think it could potentially be clarified in terms of what's doing the "providing", e.g.
|
||||||||||||||||||||||
|
||||||||||||||||||||||
- The type is countable ([§15.7.1](classes.md#1571-general)). | ||||||||||||||||||||||
- The type has an accessible instance indexer taking an argument of type `int` as its only argument. | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In contrast to another comment thread, this is an example where "able to bind Is parameter refness important to mention? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Replaced] (My fears were justified) For the refness question, maybe:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, I think we should talk about the declared parameters, rather than "taking an argument". |
||||||||||||||||||||||
- The type does not have an accessible instance indexer taking a `System.Index` as its only argument, or as its first argument with the remaining arguments being optional. | ||||||||||||||||||||||
Comment on lines
+5596
to
+5600
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think by this list, the following should not error, but it does: var dict = new X();
dict[^1] = "";
class X : Dictionary<int, string>
{
} |
||||||||||||||||||||||
|
||||||||||||||||||||||
The provided instance indexer shall have the same get and set members with matching accessibility as the `int` indexer. | ||||||||||||||||||||||
RexJaeschke marked this conversation as resolved.
Show resolved
Hide resolved
jnm2 marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The 'range' version of this called out that the return type was the same, including 'ref'. That is true here too. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't really understand what's meant by "the same get and set members" here in the first place... My guess is that this is to do with "if the int-based indexer is readable, then so is the provided Index-based indexer; likewise is the int-based indexer is writable, then so is the provided Index-based indexer" but I could be wrong. |
||||||||||||||||||||||
|
||||||||||||||||||||||
The provided instance indexer shall take the given `System.Index` and use that to call the instance indexer taking an `int`. If both the `Length` and `Count` properties exist and are accessible, `Length` is used. | ||||||||||||||||||||||
RexJaeschke marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Converting descriptive to specification language:
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Further to my last comment, there is no context here as to why either |
||||||||||||||||||||||
|
||||||||||||||||||||||
> *Note*: See §indexable-sequence-expl-support-for-index for an example of an explicitly provided `Index` indexer. If that were not defined, its equivalent would be provided by the implementation. *end note* | ||||||||||||||||||||||
|
||||||||||||||||||||||
### §indexable-sequence-support-for-range Providing support for Range | ||||||||||||||||||||||
|
||||||||||||||||||||||
#### §indexable-sequence-expl-support-for-range Explicit Range support | ||||||||||||||||||||||
|
||||||||||||||||||||||
A type having an instance indexer taking a single argument of type `System.Range`, or a first argument of that type followed by optional arguments, may be indexed as described by [§12.8.11.3](expressions.md#128113-indexer-access). | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. section change:
Suggested change
|
||||||||||||||||||||||
|
||||||||||||||||||||||
> *Example*: In [§15.9](classes.md#159-indexers), there is an example defining type `BitArray`, which stores bits in an array of `int`. Adding a `Range` indexer that returns a `BitArray` representing the bit slice designated by the Range, is simple: | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "Simple" seems to be a subjective term. What would the goal be to communicate here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jnm2 – maybe “straightforward” which doesn’t carry the same risk of offense as “simple”, or may be:
Suggested change
Wordsmith away folks! |
||||||||||||||||||||||
> | ||||||||||||||||||||||
> <!-- Example: {template:"standalone-console", name:"ExplicitRangeSupport", additionalFiles:["BitArrayPartial2.cs"], expectedOutput:["ba = >10011<","BitArray is >10011<","BitArray is >10011<","BitArray is >1<","BitArray is >1<","BitArray is ><"]} --> | ||||||||||||||||||||||
> ```csharp | ||||||||||||||||||||||
> partial class BitArray | ||||||||||||||||||||||
> { | ||||||||||||||||||||||
> public BitArray this[Range range] // note the return type | ||||||||||||||||||||||
> { | ||||||||||||||||||||||
> get | ||||||||||||||||||||||
> { | ||||||||||||||||||||||
> int startIdx = range.Start.GetOffset(Length); | ||||||||||||||||||||||
> int endIdx = range.End.GetOffset(Length); | ||||||||||||||||||||||
> int rangeLength = endIdx - startIdx; | ||||||||||||||||||||||
> BitArray newBitArray = new BitArray(rangeLength); | ||||||||||||||||||||||
> for (int i = startIdx; i < endIdx; ++i) | ||||||||||||||||||||||
> { | ||||||||||||||||||||||
> newBitArray[i - startIdx] = this[i]; | ||||||||||||||||||||||
> } | ||||||||||||||||||||||
> return newBitArray; | ||||||||||||||||||||||
> } | ||||||||||||||||||||||
> } | ||||||||||||||||||||||
> } | ||||||||||||||||||||||
> ``` | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> *end example* | ||||||||||||||||||||||
|
||||||||||||||||||||||
#### §indexable-sequence-impl-support-for-range Implicit Range support | ||||||||||||||||||||||
|
||||||||||||||||||||||
An implementation shall behave as if it provides a non-virtual instance indexer member with a single parameter of type `System.Range` for any type that meets the following criteria: | ||||||||||||||||||||||
|
||||||||||||||||||||||
- The type is countable ([§15.7.1](classes.md#1571-general)). | ||||||||||||||||||||||
- The type has an accessible instance method named `Slice` taking two arguments of type `int` as the only arguments. For type `string`, the method `Substring` is used instead of `Slice`. | ||||||||||||||||||||||
RexJaeschke marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||
> *Note*: As specified in [§12.8.11.2](expressions.md#128112-array-access), for array access, the method `System.Runtime.CompilerServices.RuntimeHelpers.GetSubArray` is used instead of `Slice`. *end note* | ||||||||||||||||||||||
Comment on lines
+5645
to
+5646
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is listed as a note, and arrays are left out of the list on the previous line. It seems like arrays should be given equal special-case status as strings. These are the two types that are the exception to needing a method named Slice. If the Roslyn compiler can't find the method RuntimeHelpers.GetSubArray, it still behaves as if it provides the range indexer, and then fails at a later stage with "CS0656 Missing compiler required member 'System.Runtime.CompilerServices.RuntimeHelpers.GetSubArray'." So the presence of this method is not a determining factor for whether the Roslyn implementation behaves as if it provides the Range indexer. I didn't check what happens if - The type is `string`, an array type, or has an accessible instance method named `Slice` [...]. Then, mentions of the Substring and GetSubArray methods could be notes informing readers what will happen in those two special cases. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If a different method is being used for arrays then it needs to be specified in normative text, not as an informative note. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And we need to think about whether There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. section change:
Suggested change
|
||||||||||||||||||||||
- The type does not have an accessible instance indexer taking a `System.Range` as its only argument, or as its first argument with the remaining arguments being optional. | ||||||||||||||||||||||
|
||||||||||||||||||||||
The provided instance indexer shall have the same accessibility and return type, including `ref` if present, as `Slice`. | ||||||||||||||||||||||
RexJaeschke marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use ref_kind, I suspect it just predates this?
Suggested change
|
||||||||||||||||||||||
|
||||||||||||||||||||||
When the type is indexed with a `System.Range`, the provided instance indexer shall take the given range and pass its start index and length as `int`s to `Slice` (or in the case of `string`, to method `Substring`). | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This sentence doesn't hold for arrays. |
||||||||||||||||||||||
|
||||||||||||||||||||||
> *Note*: See §indexable-sequence-expl-support-for-range for an example of an explicitly provided `Range` indexer. If that were not defined, its equivalent would be provided by the implementation, except that the provided indexer would call `Slice` to create and copy the slice. For type `BitArray`, `Slice` might be defined, as follows: | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> <!-- Example: {template:"standalone-console", name:"ImplicitRangeSupport", additionalFiles:["BitArrayPartial3.cs"], expectedOutput:["ba = >10011<","BitArray is >10011<","BitArray is >10011<","BitArray is >1<","BitArray is >1<","BitArray is ><"]} --> | ||||||||||||||||||||||
> ```csharp | ||||||||||||||||||||||
> partial class BitArray | ||||||||||||||||||||||
> { | ||||||||||||||||||||||
> public BitArray Slice(int startIdx, int rangeLength) | ||||||||||||||||||||||
> { | ||||||||||||||||||||||
> int endIdx = startIdx + rangeLength; | ||||||||||||||||||||||
> BitArray newBitArray = new BitArray(rangeLength); | ||||||||||||||||||||||
> for (int i = startIdx; i < endIdx; ++i) | ||||||||||||||||||||||
> { | ||||||||||||||||||||||
> newBitArray[i - startIdx] = this[i]; | ||||||||||||||||||||||
> } | ||||||||||||||||||||||
> return newBitArray; | ||||||||||||||||||||||
> } | ||||||||||||||||||||||
> } | ||||||||||||||||||||||
> ``` | ||||||||||||||||||||||
> | ||||||||||||||||||||||
> *end note* |
Uh oh!
There was an error while loading. Please reload this page.