November 19, 2014
On 11/19/14, 7:03 AM, Don wrote:
> On Tuesday, 18 November 2014 at 18:23:52 UTC, Marco Leise wrote:
>
> Weird consequence: using subtraction with an unsigned type is nearly
> always a bug.
>
> I wish D hadn't called unsigned integers 'uint'. They should have been
> called '__uint' or something. They should look ugly. You need a very,
> very good reason to use an unsigned type.
>
> We have a builtin type that is deadly but seductive.
>

I agree. An array's length makes sense as an unsigned ("an array can't have a negative length, right?") but it leads to the bugs you say. For example:

~~~
import std.stdio;

void main() {
  auto a = [1, 2, 3];
  auto b = [1, 2, 3, 4];
  if (a.length - b.length > 0) {
    writeln("Can you spot the bug that easily?");
  }
}
~~~

Yes, it makes sense, but at the same time it leads to super unintuitive math operations being involved.

Rust made the same mistake and now a couple of times I've seen bugs like these being reported. Never seen them in Java or .Net though. I wonder why...
November 19, 2014
On 11/19/14, 1:46 PM, Andrei Alexandrescu wrote:
> On 11/19/14 2:03 AM, Don wrote:
>> We have a builtin type that is deadly but seductive.
>
> I agree this applies to C and C++. Not quite to D. -- Andrei

See my response to Don. Don't you think that's counter-intuitive?

November 19, 2014
On 11/19/14, 10:21 AM, ketmar via Digitalmars-d wrote:
> On Wed, 19 Nov 2014 10:03:34 +0000
> Don via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
>> No! No! No!  This is completely wrong. Unsigned does not mean
>> "positive". It means "no sign", and therefore "wrapping
>> semantics".
>> eg length - 4 > 0, if length is 2.
>>
>> Weird consequence: using subtraction with an unsigned type is
>> nearly always a bug.
> negative length is a bug too.

How is that a bug? Can you provide some code that exhibits this?

November 19, 2014
On Wednesday, 19 November 2014 at 16:02:50 UTC, David Gileadi wrote:
> On 11/19/14, 6:57 AM, ketmar via Digitalmars-d wrote:
>> On Wed, 19 Nov 2014 13:47:50 +0000
>> Don via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>>> If I have two pencils of length 10 cm and 15 cm, then the first
>>> one is -5 cm longer than the other.
>> and again "length" is not a relation. show me pencil of length -10 cm.
>> when you substractin lengthes, you got completely different type as a
>> result, not "length" anymore. ah, that untyped real-life math! ;-)
>
> To me the salient point is that this is not just a mess with real-life math but also with math in D: lengths are unsigned but people subtract them all the time. If they're (un)lucky this will return correct values for a while, but then someday the lengths may be reversed and the values will be hugely wrong:
>
>     int[] a = [1, 2, 3];
>     int[] b = [5, 4, 3, 2, 1];
>
>     writefln("%s", b.length - a.length);  // Yup, 2
>     writefln("%s", a.length - b.length);  // WAT? 18446744073709551614
>
> This is why I agree with Don that:
>
> > Having arr.length return an unsigned type, is a dreadful
> language
> > mistake.

I'd say length being unsigned is fine. The real mistake is that the difference between two unsigned values isn't signed, which would be the most "correct" behaviour. Let people cast the result if they want wrapping (or better, use a helper function to document the intentiion).
November 19, 2014
On 11/19/14 10:13 AM, Ary Borenszweig wrote:
> On 11/19/14, 1:46 PM, Andrei Alexandrescu wrote:
>> On 11/19/14 2:03 AM, Don wrote:
>>> We have a builtin type that is deadly but seductive.
>>
>> I agree this applies to C and C++. Not quite to D. -- Andrei
>
> See my response to Don. Don't you think that's counter-intuitive?

No. -- Andrei

November 19, 2014
On 11/19/14 10:09 AM, Ary Borenszweig wrote:
> On 11/19/14, 7:03 AM, Don wrote:
>> On Tuesday, 18 November 2014 at 18:23:52 UTC, Marco Leise wrote:
>  >
>> Weird consequence: using subtraction with an unsigned type is nearly
>> always a bug.
>>
>> I wish D hadn't called unsigned integers 'uint'. They should have been
>> called '__uint' or something. They should look ugly. You need a very,
>> very good reason to use an unsigned type.
>>
>> We have a builtin type that is deadly but seductive.
>>
>
> I agree. An array's length makes sense as an unsigned ("an array can't
> have a negative length, right?") but it leads to the bugs you say. For
> example:
>
> ~~~
> import std.stdio;
>
> void main() {
>    auto a = [1, 2, 3];
>    auto b = [1, 2, 3, 4];
>    if (a.length - b.length > 0) {
>      writeln("Can you spot the bug that easily?");
>    }
> }
> ~~~
>
> Yes, it makes sense, but at the same time it leads to super unintuitive
> math operations being involved.
>
> Rust made the same mistake and now a couple of times I've seen bugs like
> these being reported. Never seen them in Java or .Net though. I wonder
> why...

There are related bugs in Java too, e.g. I remember one in binary search where (i + j) / 2 was wrong because of an overflow. Also, Java does have a package for unsigned integers so apparently it's necessary.

Andrei

November 19, 2014
Andrei Alexandrescu:

> No. -- Andrei

Yet, experience in D has shown very well that having unsigned lengths is the wrong design choice. It's a D wart.

Bye,
bearophile
November 19, 2014
Andrei Alexandrescu:

> There are related bugs in Java too, e.g. I remember one in binary search where (i + j) / 2 was wrong because of an overflow.

This is possible in D too.


> Also, Java does have a package for unsigned integers so apparently it's necessary.

This is irrelevant. No one here is saying that a system language should not have unsigned values. The discussion here is about the type of array lengths.

Bye,
bearophile
November 19, 2014
On Wednesday, 19 November 2014 at 20:40:53 UTC, bearophile wrote:
> Andrei Alexandrescu:
>
>> There are related bugs in Java too, e.g. I remember one in binary search where (i + j) / 2 was wrong because of an overflow.
>
> This is possible in D too.
>
>
>> Also, Java does have a package for unsigned integers so apparently it's necessary.
>
> This is irrelevant. No one here is saying that a system language should not have unsigned values. The discussion here is about the type of array lengths.
>
> Bye,
> bearophile

The only signed types that are able to represent all possible
array lengths on 64 bit systems are long double and cent.
November 19, 2014
On Wednesday, 19 November 2014 at 18:09:11 UTC, Ary Borenszweig wrote:
> On 11/19/14, 7:03 AM, Don wrote:
>> On Tuesday, 18 November 2014 at 18:23:52 UTC, Marco Leise wrote:
> >
>> Weird consequence: using subtraction with an unsigned type is nearly
>> always a bug.
>>
>> I wish D hadn't called unsigned integers 'uint'. They should have been
>> called '__uint' or something. They should look ugly. You need a very,
>> very good reason to use an unsigned type.
>>
>> We have a builtin type that is deadly but seductive.
>>
>
> I agree. An array's length makes sense as an unsigned ("an array can't have a negative length, right?") but it leads to the bugs you say. For example:
>
> ~~~
> import std.stdio;
>
> void main() {
>   auto a = [1, 2, 3];
>   auto b = [1, 2, 3, 4];
>   if (a.length - b.length > 0) {
>     writeln("Can you spot the bug that easily?");
>   }
> }
> ~~~
>
> Yes, it makes sense, but at the same time it leads to super unintuitive math operations being involved.
>
> Rust made the same mistake and now a couple of times I've seen bugs like these being reported. Never seen them in Java or .Net though. I wonder why...

IMO array length should be unsigned but I'd like to see unsafe operators on unsigned types illegal. It is trivial to write (a.signed - b.signed) and it should be explicit in the code, i.e. not something that the compiler will do automatically behind the scenes.

Cheers,
uri