Regarding Jeff's argument as for the advantages of programming with
numbers that are garanteed to be non-negative. I would argue that this
is also mostly valid in C/C++, where arrays are always indexed starting
with zero. Many languages allow upper /and/ lower index bounds to be
arbitrary (signed) integers, or even any other data type, provided the
programmer can specify a one-to-one mapping onto a bounded interval of
integers. Thus, non-negativity seems to be a somewhat arbitrary
guarantee (why not, for instance, strict positivity?). Furthermore,
with regard to the efficiency question (only one range-check for upper
bound instead of two for upper and lower), in C/C++ you are always
free to apply the zero-cost type cast from signed to unsigned, thereby
mapping negative numbers to large positive ones, and then range-test
only for the upper bound. This will fail for /exactly/ the cases where
the original check failed, as long as you don't rely on the upper half
of the possible range, something you (Jeff) suggested is to be avoided
anyway.