dotnet / docs

This repository contains .NET Documentation.
https://learn.microsoft.com/dotnet
Creative Commons Attribution 4.0 International
4.27k stars 5.9k forks source link

Range operators #32824

Open ygoe opened 1 year ago

ygoe commented 1 year ago

I'm confused. What does range[2..4] give me? From 2 to 4 (inclusive), which is 3 items? Or from 2 to 4 (exclusive), which is 2 to 3? Or from 2 on 4 items, which is 2 to 5? The description has very much text but nothing to find that could answer this simple question. The C# code editor tooltips and dropdowns don't even know what I'm doing here, explaining me that I'm typing a single byte offset number.

My problem is that I have this code: Encoding.ASCII.GetString(responseBody.Span[index..(index + length - 1)]) which should read length bytes starting at index but gives me one character less than length. When I still used the non-span code with buffer/offset/count, it worked and was clearly readable. Following these modern style suggestions caused me a lot of work (the range/memory stuff is just as viral as async/await) and now this problem.


Document Details

Do not edit this section. It is required for learn.microsoft.com ➟ GitHub issue linking.

gfoidl commented 1 year ago

See the actual documentation and not the draft -> Range operator ..:

The .. operator specifies the start and end of a range of indices as its operands. The left-hand operand is an inclusive start of a range. The right-hand operand is an exclusive end of a range.

ygoe commented 1 year ago

Hm, doesn't look like a draft to me. Why are there drafts in the official documentation? Shouldn't they be replaced with the current version? I googled it because I wasn't sure how you call that double-dot syntax.

That new page is a lot more helpful, but it also contains strange things:

As the preceding example shows, expression ^e is of the System.Index type.

As the preceding example shows, expression a..b is of the System.Range type.

How do these examples show that? The words "Index" and "Range" don't even appear there, so they do not show it to me. It's only that text that states it.

Then the table showing all combinations for the range operator is described as being not complete, but I think in fact only a single case is missing: ^start..end That makes me curious if the table was actually complete and that one case isn't valid? The strange order in the description of ^start.. adds to that (I understand it as "everything here is counted from the end, the start and the not provided end").

Basically the ^ from end counting looks to me like what all other languages just write as negative numbers, a thing that C# explicitly doesn't allow.

gfoidl commented 1 year ago

How do these examples show that?

By

As the preceding example shows, expression ^e is of the System.Index type. In expression ^e, the result of e must be implicitly convertible to int.

The e in the examples are 1, 2, word.Length.

That page is about "Member access operators and expressions", also there's "^e is of the Index type". So the compiler knows that ^e has to be compiled to Index. As it would be tedious to always write Index explicitly that expression got introduced and this is what the example shows.

Also that page has a link to Indices and ranges. Does this page clarify your questions?

BillWagner commented 1 year ago

Thanks @ygoe @gfoidl

@ygoe I'd like to know what the pre-span code looked like. That would help improve the docs for this feature.

The concern about the draft specs is valid. It's a point in time problem while the ECMA committee works to catchup to the current implementation. The committee is working on the features for C# 7.x right now. We anticipate that we'll start moving faster as we progress. Committee members have asked a number of clarifying questions on the older feature specs, and one result is that the new feature specs are updated with newer decisions and are more accurate.

We publish the feature specs in the interim as a reasonable compromise to get some information out while we catch up. I've been retiring those feature specs as the features are incorporated into the draft standard.

ygoe commented 1 year ago

Yes, the referenced page eventually clarified things, and I could infer it indirectly from those statements, too. It's just not the correct wording I guess. A minimal test case: "As shown here, b is 5." Even if that fact really wasn't shown anywhere, now you know, too.

The pre-span code is not in my backups, I probably wrote and modified it in one day. But it must have looked like that: Encoding.ASCII.GetString(responseBody, index, length) There is another overload of the GetString method that accepts the classic three parameters byte[] buffer, int offset, int count. I must have updated that to what I've written above, assuming that the range has two inclusive ends. But after reading up things on the page Google didn't give me, it's actually pretty simple. The exclusive end makes the minimal conversion of the code behave the same, and it was probably chosen because it needs less code in common scenarios, I get that. It just came unexpected. If somebody talks about the bytes 2 to 4, they're usually referring to a total of 3 bytes, not 2.

Maybe these draft pages should be marked more clearly as such. Google finds them as relevant, but it sounds like they're more of an internal process requirement, rather than the documentation intended to be read by users. This draft page also looked pretty chaotic to me. The intended documentation is very clear compared to this.