On Tue, 02 Apr 2013 23:26:54 -0400, Andrei Alexandrescu
<[email protected]> wrote:
On 4/2/13 11:10 PM, Steven Schveighoffer wrote:
On Tue, 02 Apr 2013 16:32:21 -0400, Walter Bright
<[email protected]> wrote:
On 4/2/2013 12:47 PM, Andrei Alexandrescu wrote:
I used to lean a lot more toward this opinion until I got to work on
a C++
codebase using signed integers as array sizes and indices. It's an
pain all over
the code - two tests instead of one or casts all over, more cases to
worry
about... changing the code to use unsigned throughout ended up being
an
improvement.
For example, with a signed array index, a bounds check is two
comparisons rather than one.
Why?
struct myArr
{
int length;
int opIndex(int idx) { if(cast(uint)idx >= cast(uint)length) throw new
RangeError(); ...}
}
-Steve
As I said - either two tests or casts all over.
But this is not "all over", it's in one place, for bounds checking.
I find that using unsigned int doesn't really hurt much, but it can make
things awkward.
For example, it's better to do addition than subtraction:
for(int i = 0; i < arr.length - 1; ++i)
{
if(arr[i] >= arr[i+1])
throw new Exception("Not sorted!");
}
This has a bug, and is better written as:
for(int i = 0; i + 1 < arr.length; ++i)
These are the kinds of things that can get you into trouble. With a
signed length, then both loops are equivalent, and we don't have that
error.
I'm not sure which is better. It feels to me that if you CAN achieve the
correct performance (even if this means casting), but the default errs on
the side of safety, that might be a better option.
-Steve