Waldek Hebisch wrote:
Russell Whitaker wrote:
The following compiles but no longer works:
program fill; var s: string(10); begin fillchar(s[1], s.capacity, ' '); writeln("ok"); end.
Do you get a message about out of range value? If yes then strictly speaking the compiler is right: s is uninitialized, so its length is set to 0, hence access to s[1] is illegal (out of range).
Yes.
In fact, I see another problem with the code above: s[1] is a single char, but fillchar acceses also s[2],... which strictly speaking is another out of bound access (but ATM compiler can not detect this problem).
Well, FillChar is low-level, working on memory directly.
I would say that fillchar is incompatible with range checking (at least now). ATM you can say:
setlength(s, 10); fillchar(s[1], s.capacity, ' ');
Yes, that's what I did in the few cases like that I had.
and I will work. However, I think that the correct way is: setlength(s, s.capacity); fillchar(s[1..length(s)], length(s), ' ');
Alternatively, you char turn range checking off.
In the future we may teach the compiler that fillchar is special, so it applies to it relaxed range checking rules, but that would require non-trivial changes in the compiler.
To some extend the compiler already knows this, that's why the first way works. I.e., it cares only about the address of the first argument (and thus only about its validity), not about the length of the memory block. Actually, that's nothing magic -- an untyped `var' parameter has the same effect. Since it's possible to write user-level routines using untyped parameters that work on memory blocks of any size, the compiler can't check them in general.
So I'd rather leave things as they are -- OTOH, making checking stricter (to the whole block) wouldn't be possible with user-level routines, OTOH, making it looser (WRT s[1]) would seem to cost quite some effort for little gain (as it's often easy to avoid the problem by reordering as here, or at worst, turn off range-checking locally).
Frank