This is an interesting example.
Off-by-one errors are extremely common, especially when you first start programming. Over time, you learn to prevent them.
Considering Delphi:
Given this declaration: var ary[10] : char; str[10] : string;
One might be tempted to write:
for var i := 0 to 10 do ary[ i ] := '';
and similarly
for var i := 0 to 10 do str[ i ] := '';
The first loop would blow up when i = 10, and the second would blow up when i = 0. And the compiler would fail to flag either as a possible problem.
A smarter programmer might write:
for var i := Min(ary) to Max(ary) do ary[ i ] := '';
for var i := Min(str) to Max(str) do str[ i ] := '';
But the safest way is to use this syntax (when it makes sense):
for var ch in ary do xyz(ch);
for var ch in str do xyz(ch);
There are other variations that can attract off-by-one errors (while ... do, repeat ... until, etc.) that the compiler is helpless to do anything about.
What's needed is a syntactical way to totally AVOID such off-by-one errors in the first place.
Well, the for ... in syntax is the safest, but it's not valid in some use cases -- like if you want to initialize the contents of the array, because it yields a value, not an index. Some languages have the ability to let you say "foreach ..." or "for ... each ...", but that's still a decade away from showing up in Delphi, if it ever will.
So we're left to use far less efficient libraries to provide these common-sense solutions, or just go bare-knuckle and let the cards fall where they may.
There are plenty of ways to make the language "safer" in many such respects, but if nobody is willing to actually make the compiler changes needed then it's a wasted discussion.