Skip to content

Conversation

Nigel-Ecma
Copy link
Contributor

Alternative to #605

  • Add support for Index & Ranges
  • Details of types and "implicit support" in new chapter, temporarily at end to reduce lots of changes due to renumbering
  • Attempts to avoid all implementation specific details from source material
  • Covers dynamic binding, associativity, etc.
  • Updates grammar test reference files (adding a new layer to the expression stack changes the tree but not the parse). These files can be ignored for review (they are machine generated).
  • Adds a new grammar test with Index & Range samples

@Nigel-Ecma Nigel-Ecma requested a review from a team July 12, 2025 04:06
@RexJaeschke
Copy link
Contributor

RexJaeschke commented Jul 12, 2025

Editorial Nits

I can take care of the following once we merge this PR:

  1. Change all code block starts from CSharp to csharp.
  2. Change all "indicies" to "indices".
  3. Change all "[C|c]hapter" to "[C|c]lause" Done by PR Replace chapter/section with clause/subclause, and clause with subclause, as appropriate #1373.
  4. Make consistent with the existing spec the use of "that" vs. "which" and associated punctuation.
  5. Add test harnesses to all examples.
  6. Change all "must" in normative text to "shall".
  7. Make sure that all the (currently) hard-coded references in the new clause 24, "Extended Indexing and Slicing," are made relative.

@RexJaeschke
Copy link
Contributor

In email Nigel sent to active TG2 members on 2025-07-12, Subject: [TG2] Re: PR#1369 Add support for Index & Range, he wrote

The types added in §C.3 have documentation comments. Good, bad or ugly?

I've generalized that question by linking (the currently Parked) Issue 1135 to here, and asked for priority on that Issue next call.

@Nigel-Ecma
Copy link
Contributor Author

Thanks for quick the review, I'll work my way down.

Editorial Nits

I can take care of the following once we merge this PR:

  1. Change all code block starts from CSharp to csharp.

Will be in next commit.

  1. Change all "indicies" to "indices".

This one beat my spell-checker, will be in the commit.

  1. Change all "[C|c]hapter" to "[C|c]lause"

Not sure about this one.

While “chapter” does not occur in the text often (I think it is used a few times in 3 out of 7 versions) when it does it is referring to a whole §N (no .M), i.e. a whole chapter ;-) Further it is used in the page headings in most versions including the last one, v7. I like that it unambiguously refers to the whole chapter. We typically use “subclause” (which GitHub has now replaced twice with “subclass” and I've fixed it, I may not spot this every time!) for a §N(.M)+, but not always, sometimes I think to refer to a chapter, and sometimes to refer to a language construct – some examples:

  • subclause, §15.7.3 “This clause applies to both properties…”
  • chapter, §12.1 “This clause defines the syntax…”
  • language construct, §21.4 “Once a matching catch clause is found…”
  • most things, §6.2.4 “The syntactic grammar of C# is presented in the clauses, subclauses, and annexes that follow this subclause.”
  • does clause/subclause include nested subclauses, sometimes we elaborate:
    • §23.1 “The remainder of this clause, including all of its subclauses, is conditionally normative.”
    • §12.8.9.1 “The remainder of this subclause and the following sibling subclauses are conditionally normative.”

I can see an argument for “chapter”, a review of how (sub)clause is used (yikes!), and acknowledge the usages I added are currently the only ones in v8.

  1. Make consistent with the existing spec the use of "that" vs. "which" and associated punctuation.
  2. Add test harnesses to all examples.

These two are definitely more @RexJaeschke’s area than mine, I happily leave them to him, thanks :-)

@RexJaeschke
Copy link
Contributor

Re chapter/clause usage. Until we adopted the wrapper spec for ISO to avoid complying completely with their style, we followed ISO rules in this regard. And we might as well keep doing that to be consistent.

  • An ISO spec had clauses rather than chapters.
  • An ISO spec had subclauses rather than sections.
  • An ISO spec does not have subsubclauses; subclause is used for all subordinate levels.

@Nigel-Ecma Nigel-Ecma self-assigned this Jul 13, 2025
@Nigel-Ecma
Copy link
Contributor Author

Re chapter/clause usage. Until we adopted the wrapper spec for ISO to avoid complying completely with their style, we followed ISO rules in this regard. And we might as well keep doing that to be consistent.

  • An ISO spec had clauses rather than chapters.
  • An ISO spec had subclauses rather than sections.
  • An ISO spec does not have subsubclauses; subclause is used for all subordinate levels.

Isn't it also a requirement that all text is in subclauses (the reason for all the §N.1 General subclauses)?

So a clause has no text in it and something like “see clause §N“ can be taken to mean the whole clause and all the subclauses, i.e. what “chapter” has been used for occasionally over the versions and now in this PR.

Does this mean something like “see clause §N.M” should use subclause, or does the “.M” allow clause to be used?

Anyway, if this is definitive we need an issue to remove “Chapter” from the page headers in the final Standard (where it is in most ECMA releases).

I suspect that clause might be misused to mean subclause, and that it is not maybe clear that clause means the whole chapter, so so cleanup might be in order. There are 107 uses (in draft-v8 at the point this PR branched), I think most refer to language clauses so are fine so the job isn’t too daunting…

@RexJaeschke
Copy link
Contributor

@Nigel-Ecma:

Isn't it also a requirement that all text is in subclauses (the reason for all the §N.1 General subclauses)?

Yes, Any clause or subclause containing a subclause cannot have its own text. Specifically, "hanging paragraphs are not allowed."

So a clause has no text in it and something like “see clause §N“ can be taken to mean the whole clause and all the subclauses, i.e. what “chapter” has been used for occasionally over the versions and now in this PR.

Exactly! This is the reason ISO has this requirement. A reference of §N always means all of N and its subordinates, and a reference of §N.M always means all of N.M and its subordinates.

Does this mean something like “see clause §N.M” should use subclause, or does the “.M” allow clause to be used?

N.M is a subclause, not a clause. ISO only uses the word "Clause" in a reference when the whole clause is intended. They do not use "subclause" for N.M, but rather, say nothing, so "see §N.M" is used instead. That said, ISO does not allow the use § in references, but I've always has it in documentation I've written, and I introduced it in V1.

Anyway, if this is definitive we need an issue to remove “Chapter” from the page headers in the final Standard (where it is in most ECMA releases).

Good observation. When we are ready to push out a new edition, Jon gives me the final generated Word version and I do light formatting on it before submitting it to Ecma. I just added to my list of "things to do in that process" to change the clause headers from "Chapter" to "Clause." Or we could simply omit that word altogether. In any event, we don't say "Annex" for each Annex header.

I suspect that clause might be misused to mean subclause, and that it is not maybe clear that clause means the whole chapter, so so cleanup might be in order. There are 107 uses (in draft-v8 at the point this PR branched), I think most refer to language clauses so are fine so the job isn’t too daunting…

Once we've discussed this I can clean this up.

@RexJaeschke RexJaeschke added the meeting: priority Review before meeting. Merge, merge with issues, or reject at the next TC49-TC2 meeting label Jul 14, 2025
@Nigel-Ecma
Copy link
Contributor Author

@RexJaeschke wrote:

[snip] That said, ISO does not allow the use § in references, but I've always has it in documentation I've written, and I introduced it in V1.

Well of course they don’t, it is the section sign and they are clearly anti-section ;-), we like §, M§GA (ducking) ;-) Are there enough ;-)’s?

With the plan to remove all the occurrences of chapter and aim for consistency on the use of (sub)clause, the need for things like “this subclause and its subclauses”, et al., the four that are down to me will be gone in the next commit.

Copy link
Contributor

@jskeet jskeet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of tiny nits/typos, but I'm generally liking the approach here a lot.

Copy link
Contributor

@MadsTorgersen MadsTorgersen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very impressive PR! I read through everything in the standard folder, and as far as I can see, the whole thing checks out.

@@ -784,6 +784,10 @@
- [§23.8.3](unsafe-code.md#2383-fixed-size-buffers-in-expressions) Fixed-size buffers in expressions
- [§23.8.4](unsafe-code.md#2384-definite-assignment-checking) Definite assignment checking
- [§23.9](unsafe-code.md#239-stack-allocation) Stack allocation
- [§24](ranges.md#24-ranges-and-slicing) Ranges and Slicing
Copy link
Contributor

@RexJaeschke RexJaeschke Aug 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- [§24](ranges.md#24-ranges-and-slicing) Ranges and Slicing
- [§24](ranges.md#24-ranges-and-slicing) Extended indexing and slicing

@@ -0,0 +1,309 @@
# 24 Extended Indexing and Slicing
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# 24 Extended Indexing and Slicing
# 24 Extended indexing and slicing

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm mildly amused that the name of the file doesn't occur anywhere within its title. How much do we care?

@@ -112,7 +112,9 @@ Elements of arrays created by *array_creation_expression*s are always initialize

## 17.4 Array element access

Array elements are accessed using *element_access* expressions ([§12.8.12.2](expressions.md#128122-array-access)) of the form `A[I₁, I₂, ..., Iₓ]`, where `A` is an expression of an array type and each `Iₑ` is an expression of type `int`, `uint`, `long`, `ulong`, or can be implicitly converted to one or more of these types. The result of an array element access is a variable, namely the array element selected by the indices.
Array elements are accessed using the *array access* variant of *element_access* expressions ([§12.8.12.2](expressions.md#128122-array-access)) of the form `A[I₁, I₂, ..., Iₓ]`, where `A` is an expression of an array type and each `Iₑ` is an expression of type `int`, `uint`, `long`, `ulong`, or can be implicitly converted to one or more of these types. The result of an array access is a variable reference (§9.5) to the array element selected by the indices.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Array elements are accessed using the *array access* variant of *element_access* expressions ([§12.8.12.2](expressions.md#128122-array-access)) of the form `A[I₁, I₂, ..., Iₓ]`, where `A` is an expression of an array type and each `Iₑ` is an expression of type `int`, `uint`, `long`, `ulong`, or can be implicitly converted to one or more of these types. The result of an array access is a variable reference (§9.5) to the array element selected by the indices.
Array elements are accessed using the *array access* variant of *element_access* expressions ([§12.8.12.2](expressions.md#128122-array-access)) of the form `A[I₁, I₂, ..., Iₓ]`, where `A` is an expression of an array type and each `Iₑ` is an expression of type `int`, `uint`, `long`, `ulong`, or can be implicitly converted to one or more of these types. The result of an array access is a variable reference ([§9.5](variables.md#95-variable-references)) to the array element selected by the indices.

Array elements are accessed using *element_access* expressions ([§12.8.12.2](expressions.md#128122-array-access)) of the form `A[I₁, I₂, ..., Iₓ]`, where `A` is an expression of an array type and each `Iₑ` is an expression of type `int`, `uint`, `long`, `ulong`, or can be implicitly converted to one or more of these types. The result of an array element access is a variable, namely the array element selected by the indices.
Array elements are accessed using the *array access* variant of *element_access* expressions ([§12.8.12.2](expressions.md#128122-array-access)) of the form `A[I₁, I₂, ..., Iₓ]`, where `A` is an expression of an array type and each `Iₑ` is an expression of type `int`, `uint`, `long`, `ulong`, or can be implicitly converted to one or more of these types. The result of an array access is a variable reference (§9.5) to the array element selected by the indices.

Array elements of single-dimensional arrays can also be accessed using an array access expression where the sole index, `I₁`, is an expression of type `Index`, `Range`, or can be implicitly converted to one or both of these types. If `I₁` is of type `Index`, or has been implicitly converted to it, then the result of the array access is a variable reference to the array element selected by the index value. If `I₁` is of type `Range`, or has been implicitly converted to it, then the result of the element access is a new array formed from a shallow copy of the array elements with indices in the `Range`, maintaining the element order.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Array elements of single-dimensional arrays can also be accessed using an array access expression where the sole index, `I₁`, is an expression of type `Index`, `Range`, or can be implicitly converted to one or both of these types. If `I₁` is of type `Index`, or has been implicitly converted to it, then the result of the array access is a variable reference to the array element selected by the index value. If `I₁` is of type `Range`, or has been implicitly converted to it, then the result of the element access is a new array formed from a shallow copy of the array elements with indices in the `Range`, maintaining the element order.
Array elements of single-dimensional arrays can also be accessed using an array access expression where the sole index, `I₁`, is an expression of type `Index`, `Range`, or can be implicitly converted to one or both of these types. If `I₁` is of type `Index`, or has been implicitly converted to that type, then the result of the array access is a variable reference to the array element selected by the index value. If `I₁` is of type `Range`, or has been implicitly converted to that type, then the result of the element access is a new array formed from a shallow copy of the array elements with indices in the `Range`, maintaining the element order.

<!-- markdownlint-disable MD028 -->

<!-- markdownlint-enable MD028 -->
> > > *Note:* A range of elements of an array cannot be assigned to using an array access. This differs from indexer accesses (§12.8.12.3) which may, but need not, support assignment to a range of indices specified by a `Range` value. *end note*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
> > > *Note:* A range of elements of an array cannot be assigned to using an array access. This differs from indexer accesses (§12.8.12.3) which may, but need not, support assignment to a range of indices specified by a `Range` value. *end note*
> > > *Note:* A range of elements of an array cannot be assigned to using an array access. This differs from indexer accesses ([§12.8.12.3](expressions.md#128123-indexer-access)) which may, but need not, support assignment to a range of indices specified by a `Range` value. *end note*

> > > *Note:* A range of elements of an array cannot be assigned to using an array access. This differs from indexer accesses (§12.8.12.3) which may, but need not, support assignment to a range of indices specified by a `Range` value. *end note*

- Otherwise:
- The result of evaluating the array access is a variable reference (§9.5) of the element type of the array.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- The result of evaluating the array access is a variable reference (§9.5) of the element type of the array.
- The result of evaluating the array access is a variable reference ([§9.5](variables.md#95-variable-references)) of the element type of the array.


#### §string-access String access

For a string access the *argument_list* of the *element_access* shall contain a single unnamed value argument (§15.6.2.2) which shall be:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
For a string access the *argument_list* of the *element_access* shall contain a single unnamed value argument (§15.6.2.2) which shall be:
For a string access the *argument_list* of the *element_access* shall contain a single unnamed value argument ([§15.6.2.2](classes.md#15622-value-parameters)) which shall be:

new Index(x, true)
```

As with the other *unary_expression*s the operand may have a compile-time type of `dynamic` (§12.9.1) and be dynamically bound (§12.3.3). The compile-time type of the result is always `Index`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
As with the other *unary_expression*s the operand may have a compile-time type of `dynamic` (§12.9.1) and be dynamically bound (§12.3.3). The compile-time type of the result is always `Index`.
As with the other *unary_expression*s the operand may have a compile-time type of `dynamic` ([§12.9.1](expressions.md#1291-general)) and be dynamically bound ([§12.3.3](expressions.md#1233-dynamic-binding)). The compile-time type of the result is always `Index`.

Range operator ..(Index x, Index y);
```

The range operator is not overloadable (§12.4.3).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The range operator is not overloadable (§12.4.3).
The range operator is not overloadable ([§12.4.3](expressions.md#1243-operator-overloading)).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tool will add this automatically.


A lifted ([§12.4.8](expressions.md#1248-lifted-operators)) form of the range operator is also predefined.

The range operator is non-associative (§12.4.2).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The range operator is non-associative (§12.4.2).
The range operator is non-associative ([§12.4.2](expressions.md#1242-operator-precedence-and-associativity)).


> *Note*: The model does not require that a slice, unlike an element, of the type can be set, but a type may support it as an extension of the model. *end note*

The model is supported for single-dimensional arrays (§12.8.12.2) and strings (§string-access).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The model is supported for single-dimensional arrays (§12.8.12.2) and strings (§string-access).
The model is supported for single-dimensional arrays ([§12.8.12.2](expressions.md#128122-array-access)) and strings (§string-access).


The model is supported for single-dimensional arrays (§12.8.12.2) and strings (§string-access).

The model can be supported by any class, struct or interface type which provides appropriate indexers (§15.9) which implement the model semantics.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The model can be supported by any class, struct or interface type which provides appropriate indexers (§15.9) which implement the model semantics.
The model can be supported by any class, struct or interface type which provides appropriate indexers ([§15.9](classes.md#159-indexers)) which implement the model semantics.


> *Note:* `Index` values are unordered as they are abstract indices, it is in general impossible to determine whether a from-end index comes before or after a from start index without reference to a sequence length. Once converted to concrete indices, e.g. by `GetOffset`, those concrete indices are comparable. *end note*

`Index` values may be directly used in the *argument_list* of an *element_access* expression (§12.8.12) which is:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
`Index` values may be directly used in the *argument_list* of an *element_access* expression (§12.8.12) which is:
`Index` values may be directly used in the *argument_list* of an *element_access* expression ([§12.8.12](expressions.md#12812-element-access)) which is:


`Index` values may be directly used in the *argument_list* of an *element_access* expression (§12.8.12) which is:

- an array access and the target is a single-dimensional array (§12.8.12.2);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- an array access and the target is a single-dimensional array (§12.8.12.2);
- an array access and the target is a single-dimensional array ([§12.8.12.2](expressions.md#128122-array-access));


- an array access and the target is a single-dimensional array (§12.8.12.2);
- a string access (§string-access)
- an indexer access and the target type has an indexer with corresponding parameters of either `Index` type (§12.8.12.3) or of a type to which `Index` values are implicitly convertible; or
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- an indexer access and the target type has an indexer with corresponding parameters of either `Index` type (§12.8.12.3) or of a type to which `Index` values are implicitly convertible; or
- an indexer access and the target type has an indexer with corresponding parameters of either `Index` type ([§12.8.12.3](expressions.md#128123-indexer-access)) or of a type to which `Index` values are implicitly convertible; or


> *Note:* `Range` values are unordered both as they are abstract and there is no unique ordering relation. Once converted to a concrete start and length, e.g. by `GetOffsetAndLength`, an ordering relation could be defined. *end note*

`Range` values can be directly used in the *argument_list* of an *element_access* expression (§12.8.12) which is:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
`Range` values can be directly used in the *argument_list* of an *element_access* expression (§12.8.12) which is:
`Range` values can be directly used in the *argument_list* of an *element_access* expression ([§12.8.12.2](expressions.md#128122-array-access)) which is:


`Range` values can be directly used in the *argument_list* of an *element_access* expression (§12.8.12) which is:

- an array access and the target is a single-dimensional array (§12.8.12.2);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- an array access and the target is a single-dimensional array (§12.8.12.2);
- an array access and the target is a single-dimensional array ([§12.8.12.2](expressions.md#128122-array-access));


If an *element_access* expression (§12.8.12) of the form `E[A]`; where `E` has type `T` and `A` is a single expression implicitly convertible to `Index` or `Range`; fails to be identified as:

- an array access (§12.8.12.2),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- an array access (§12.8.12.2),
- an array access ([§12.8.12.2](expressions.md#128122-array-access)),


### 24.4.1 General

If an *element_access* expression (§12.8.12) of the form `E[A]`; where `E` has type `T` and `A` is a single expression implicitly convertible to `Index` or `Range`; fails to be identified as:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
If an *element_access* expression (§12.8.12) of the form `E[A]`; where `E` has type `T` and `A` is a single expression implicitly convertible to `Index` or `Range`; fails to be identified as:
If an *element_access* expression ([§12.8.12](expressions.md#12812-element-access)) of the form `E[A]`; where `E` has type `T` and `A` is a single expression implicitly convertible to `Index` or `Range`; fails to be identified as:

- an array access and the target is a single-dimensional array (§12.8.12.2);
- a string access (§string-access);
- an indexer access and the target type has an indexer with corresponding parameters of either `Range` type (§12.8.12.3) or of a type to which `Range` values are implicitly convertible; or
- an indexer access (§12.8.12.3) and the target type conforms to a sequence pattern for which implicit `Range` support is specified (§24.4.3).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- an indexer access (§12.8.12.3) and the target type conforms to a sequence pattern for which implicit `Range` support is specified (§24.4.3).
- an indexer access ([§12.8.12.3](expressions.md#128123-indexer-access)) and the target type conforms to a sequence pattern for which implicit `Range` support is specified (§24.4.3).


- an array access and the target is a single-dimensional array (§12.8.12.2);
- a string access (§string-access);
- an indexer access and the target type has an indexer with corresponding parameters of either `Range` type (§12.8.12.3) or of a type to which `Range` values are implicitly convertible; or
Copy link
Contributor

@RexJaeschke RexJaeschke Aug 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- an indexer access and the target type has an indexer with corresponding parameters of either `Range` type (§12.8.12.3) or of a type to which `Range` values are implicitly convertible; or
- an indexer access and the target type has an indexer with corresponding parameters of either `Range` type ([§??](???)) or of a type to which `Range` values are implicitly convertible; or


- an array access (§12.8.12.2),
- a string access (§string-access), or
- an indexer access (§12.8.12.3) as `T` provides no suitable accessible indexer
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- an indexer access (§12.8.12.3) as `T` provides no suitable accessible indexer
- an indexer access ([§12.8.12.3](expressions.md#128123-indexer-access)) as `T` provides no suitable accessible indexer


### 24.4.3 Implicit Range support

If in any context an *element_access* expression (§12.8.12) of the form `E[A]`; where `E` has type `T` and `A` is a single expression implicitly convertible to `Range`; is not valid (§24.4.1) then if in the same context:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
If in any context an *element_access* expression (§12.8.12) of the form `E[A]`; where `E` has type `T` and `A` is a single expression implicitly convertible to `Range`; is not valid (§24.4.1) then if in the same context:
If in any context an *element_access* expression ([§12.8.12](expressions.md#12812-element-access)) of the form `E[A]`; where `E` has type `T` and `A` is a single expression implicitly convertible to `Range`; is not valid (§24.4.1) then if in the same context:

Copy link
Member

@BillWagner BillWagner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm ready to approve this. This is great workk.

There are some discussion items for our meeting to resolve though.

- The starting offset, *S*, and number of items, *N*, for `A` with respect to *L* are determined as described for `GetOffsetAndLength` (§24.3).
- The result of the string access is a new string formed by copying the *N* characters of `P` starting from *S*, if *N* is zero the new string is empty.

> > > *Note:* Both *S* and *N* may be zero (§24.3). Indexing an empty string is usually invalid, however indexing with an empty range starting at zero is valid and returns an empty string. The defintion also allows *S* to be *L*, the past-end index (§24.1), in which case *N* will be zero and an empty string returned. *end note*
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we've consistently used this form, which might be easier for the Word Converter:

Suggested change
> > > *Note:* Both *S* and *N* may be zero (§24.3). Indexing an empty string is usually invalid, however indexing with an empty range starting at zero is valid and returns an empty string. The defintion also allows *S* to be *L*, the past-end index (§24.1), in which case *N* will be zero and an empty string returned. *end note*
> *Note:* Both *S* and *N* may be zero (§24.3). Indexing an empty string is usually invalid, however indexing with an empty range starting at zero is valid and returns an empty string. The defintion also allows *S* to be *L*, the past-end index (§24.1), in which case *N* will be zero and an empty string returned. *end note*

Comment on lines +3656 to +3658
### §hat-operator Hat operator

The unary `^` operator is called the *hat* operator. The hat operator is not overloadable (§12.4.3) and there is a single predefined hat operator:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still not thrilled with "hat operator". While I'm not sold on any of these, here are some alternatives:

  • "end operator"
  • "reverse index operator"
  • "from end operator" (I like this one least)
  • "tail end operator"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interestingly, I like "from end operator" most as it corresponds with Index.FromEnd. (I could live with "index-from-end operator" as well, to be even clearer...)

Range operator ..(Index x, Index y);
```

The range operator is not overloadable (§12.4.3).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tool will add this automatically.

>
> *end note*

## 24.2 The Index type
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should discuss these two sections.

It's great work, but we have steadfastly avoided defining the semantics for library types. I see your point, but I'm concerned about increasing our workload when we are almost 6 releases behind.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I'm okay with defining the semantics of just Index and Range themselves, but not the semantics of how they're used.

Is the workload concern in terms of ongoing maintenance beyond the initial definition that has already been provided?

(No need to respond here - let's definitely discuss in the meeting.)

@@ -1823,7 +1822,7 @@ null_forgiving_operator
;
```

*Note*: The postfix null-forgiving and prefix logical negation operators ([§12.9.4](expressions.md#1294-logical-negation-operator)), while represented by the same lexical token (`!`), are distinct. Only the latter may be overriden ([§15.10](classes.md#1510-operators)), the definition of the null-forgiving operator is fixed. *end note*
*Note*: The postfix null-forgiving and prefix logical negation operators ([§12.9.4](expressions.md#1294-logical-negation-operator)), while represented by the same lexical token (`!`), are distinct. Only the latter may be overridden ([§15.10](classes.md#1510-operators)), the definition of the null-forgiving operator is fixed. *end note*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be overloaded rather than overridden?


If the *primary_expression* of an *element_access* is:

- a value of *array_type*, the *element_access* is an array access ([§12.8.12.2](expressions.md#128122-array-access));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something bothers me about the first part of this sentence; it doesn't quite sit right with me.

Would "a value of an array_type" be better? I'm unsure.

- The value of `P` is checked to be valid. If the value of `P` is `null`, a `System.NullReferenceException` is thrown and no further steps are executed.
- If the preceding steps have produced a single index value of type `Range` then:
- Let *L* be the length of the array referenced by `P`.
- `A` is checked to be valid with respect to *L* (§24.3), if it is not then a `System.ArgumentOutOfRangeException` is thrown and no further steps are executed.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly a period or semi-colon instead of a comma? (These feel like two complete sentences, effectively.)

- Let *L* be the length of the array referenced by `P`.
- `A` is checked to be valid with respect to *L* (§24.3), if it is not then a `System.ArgumentOutOfRangeException` is thrown and no further steps are executed.
- The starting offset, *S*, and number of items, *N*, for `A` with respect to *L* are determined as described for `GetOffsetAndLength` (§24.3).
- A new array is created from a shallow copy of the *N* elements of `P` starting at index *S*, if *N* is zero the new array has zero elements. This array becomes the result of the array access.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- A new array is created from a shallow copy of the *N* elements of `P` starting at index *S*, if *N* is zero the new array has zero elements. This array becomes the result of the array access.
- A new array is created from a shallow copy of the *N* elements of `P` starting at index *S*. If *N* is zero the new array has zero elements. This array becomes the result of the array access.

@@ -2254,9 +2316,17 @@ The binding-time processing of an indexer access of the form `P[A]`, where `P` i
- If `I` is applicable with respect to `A` ([§12.6.4.2](expressions.md#12642-applicable-function-member)) and `S` is a class type other than `object`, all indexers declared in an interface are removed from the set.
- If the resulting set of candidate indexers is empty, then no applicable indexers exist, and a binding-time error occurs.
- The best indexer of the set of candidate indexers is identified using the overload resolution rules of [§12.6.4](expressions.md#1264-overload-resolution). If a single best indexer cannot be identified, the indexer access is ambiguous, and a binding-time error occurs.
- The index expressions of the *argument_list* are evaluated in order, from left to right. The result of processing the indexer access is an expression classified as an indexer access. The indexer access expression references the indexer determined in the step above, and has an associated instance expression of `P` and an associated argument list of `A`, and an associated type that is the type of the indexer. If `T` is a class type, the associated type is picked from the first declaration or override of the indexer found when starting with `T` and searching through its base classes.
- The accessors of the best indexer are checked:
- If the indexer access is the target of an assignment then the indexer shall have a set or ref get accessor, if not a binding-time error occurs;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not thrilled about the comma here either, but within the context it's harder to fix.

Comment on lines +3656 to +3658
### §hat-operator Hat operator

The unary `^` operator is called the *hat* operator. The hat operator is not overloadable (§12.4.3) and there is a single predefined hat operator:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interestingly, I like "from end operator" most as it corresponds with Index.FromEnd. (I could live with "index-from-end operator" as well, to be even clearer...)

@@ -0,0 +1,309 @@
# 24 Extended Indexing and Slicing
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm mildly amused that the name of the file doesn't occur anywhere within its title. How much do we care?

>
> *end note*

## 24.2 The Index type
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I'm okay with defining the semantics of just Index and Range themselves, but not the semantics of how they're used.

Is the workload concern in terms of ongoing maintenance beyond the initial definition that has already been provided?

(No need to respond here - let's definitely discuss in the meeting.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
meeting: priority Review before meeting. Merge, merge with issues, or reject at the next TC49-TC2 meeting
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants