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