bearophile can say "i told you so" (re uint->int implicit conv)

Steven Schveighoffer schveiguy at yahoo.com
Wed Apr 3 07:43:06 PDT 2013


On Tue, 02 Apr 2013 23:26:54 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail at erdani.org> wrote:

> On 4/2/13 11:10 PM, Steven Schveighoffer wrote:
>> On Tue, 02 Apr 2013 16:32:21 -0400, Walter Bright
>> <newshound2 at digitalmars.com> 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


More information about the Digitalmars-d mailing list