number ranges
H. S. Teoh
hsteoh at quickfur.ath.cx
Mon Jan 17 22:06:47 UTC 2022
On Mon, Jan 17, 2022 at 09:37:31PM +0000, forkit via Digitalmars-d-learn wrote:
> On Monday, 17 January 2022 at 11:58:18 UTC, Paul Backus wrote:
> >
> > This kind of half-open interval, which includes the lower bound but
> > excludes the upper bound, is used in programming because it lets you
> > write
> >
> > foreach (i; 0 .. array.length) writef("%s ", array[i]);
> >
> > ...without going past the end of the array.
>
> Yes. But the intent here is clearly stated and cannot be misunderstood
> -> array.length
>
> Whereas 1..5 is just an opportunity to shoot yourself in the foot.
The compiler cannot discern intent. Both `5` and `array.length` are
expressions, as far as the compiler is concerned. So is `5 +
(array.length - sin(x))/2*exp(array2.length)`, for that matter. The
compiler does not understand what the programmer may have intended; it
simply follows what the spec says.
Of course, to a *human* the semantics of `1..5` can be totally confusing
if you're not used to it. The bottom-line is, in D (and in other C-like
languages) you just have to get used to 0-based indexing, because
ultimately it actually makes more sense than the 1-based counting scheme
we were taught in school. 1-based counting schemes are full of
exceptions and off-by-1 errors; it's needlessly complex and hard for the
mortal brain to keep track of all the places where you have to add or
subtract 1. Whereas in 0-based index schemes, you *always* count from
0, and you always use `<` to check your bounds, and you can do
arithmetic with indices just by adding and subtracting as usual, without
off-by-1 errors.
Basically,
foreach (i; a .. b)
is equivalent to:
for (auto i = a; i < b; i++)
Just think of that way and it will make sense.
And never ever write 1..n unless you actually intend to skip the first
element. Remember: 0-based counting, not 1-based counting. You always
start from 0, and count up to (but not including) n. Which also means
you should always write `<`, never write `<=`. So your upper bound is
always the element *past* the last one. I.e., it's the index at which a
new element would be added if you were appending to your list. I.e., the
index at which a new element should be added is simply array.length (not
array.length+1 or array.length-1 or any of that error-prone crap that
nobody can remember).
If you adhere to these simple rules, you'll never need to add or
subtract 1 to your counters, loop indices, and lengths (because nobody
can remember when to do that, so not having to do it significantly
reduces the chances of bugs).
T
--
People say I'm arrogant, and I'm proud of it.
More information about the Digitalmars-d-learn
mailing list