Jump to page: 1 2 3
Thread overview
Providing implicit conversion of
Jan 21, 2024
Gavin Gray
Jan 22, 2024
bachmeier
Jan 22, 2024
Nick Treleaven
Jan 22, 2024
bachmeier
Jan 23, 2024
Danilo
Jan 22, 2024
Siarhei Siamashka
Re: Providing implicit conversion of - memory-safety
Jan 23, 2024
Nick Treleaven
Jan 23, 2024
bachmeier
Jan 23, 2024
Renato
Jan 23, 2024
bachmeier
Jan 23, 2024
Renato
Jan 23, 2024
Siarhei Siamashka
Jan 24, 2024
bachmeier
Jan 24, 2024
Renato
Jan 24, 2024
Siarhei Siamashka
Jan 23, 2024
Danilo
Jan 24, 2024
bachmeier
Jan 24, 2024
Renato
Jan 22, 2024
Nick Treleaven
Jan 22, 2024
Siarhei Siamashka
Jan 23, 2024
Danilo
Jan 23, 2024
Nick Treleaven
Jan 22, 2024
thinkunix
Jan 22, 2024
bachmeier
Jan 22, 2024
Danilo
January 21, 2024

The following code:

ulong charlie = 11;
long johnstone = std.algorithm.comparison.max(0, -charlie);
writeln(format!"johnstone %s"(johnstone));

Results in (without any warning(s)):
johnstone -11

However you choose to look at it, this means -11 > 0 (regardless of all arguments concerning implicit conversions, 1's and 2's complements, being efficient, etc).

The language should not allow unary unsigned anything.

January 22, 2024

On Sunday, 21 January 2024 at 16:05:40 UTC, Gavin Gray wrote:

>

The following code:

ulong charlie = 11;
long johnstone = std.algorithm.comparison.max(0, -charlie);
writeln(format!"johnstone %s"(johnstone));

Results in (without any warning(s)):
johnstone -11

However you choose to look at it, this means -11 > 0 (regardless of all arguments concerning implicit conversions, 1's and 2's complements, being efficient, etc).

The language should not allow unary unsigned anything.

This is unlikely to get fixed, just due to the nature of D's philosophy when it comes to C compatibility.

It would also break a lot of existing code.

-Steve

January 22, 2024

On Monday, 22 January 2024 at 01:14:06 UTC, Steven Schveighoffer wrote:

>

On Sunday, 21 January 2024 at 16:05:40 UTC, Gavin Gray wrote:

>

The following code:

ulong charlie = 11;
long johnstone = std.algorithm.comparison.max(0, -charlie);
writeln(format!"johnstone %s"(johnstone));

Results in (without any warning(s)):
johnstone -11

However you choose to look at it, this means -11 > 0 (regardless of all arguments concerning implicit conversions, 1's and 2's complements, being efficient, etc).

The language should not allow unary unsigned anything.

This is unlikely to get fixed, just due to the nature of D's philosophy when it comes to C compatibility.

It would also break a lot of existing code.

-Steve

Well there was no problem breaking my code for this (which you even proposed should be fixed):

foreach(int i, v; arr) {
  // i is not an int until you do i.to!int
}

The compiler knows it's converting from a ulong to a long:

ulong a = -11;
writeln(a);
// 18446744073709551605
long b = a;
writeln(b);
// -11

It's impossible for both to be the intended behavior. Anyone doing that on purpose (which I suspect is extremely rare) would be doing it because they want b equal to 18446744073709551605. I don't see why this should be treated the same as an int to long conversion because it very much changes the value.

There needs to be a safe arithmetic mode because the current behavior of double j = 10 / 3; is not what anyone expects and is a bug 100% of the time. I've said multiple times that it's silly to spend so much time on memory safety if the language is going to allow stuff like this without a simple way to prevent it.

January 22, 2024
Gavin Gray via Digitalmars-d-learn wrote:
> The following code:
> 
>    ulong charlie = 11;
>    long johnstone = std.algorithm.comparison.max(0, -charlie);
>    writeln(format!"johnstone %s"(johnstone));
> 
> Results in (without any warning(s)):
> johnstone -11
> 
> However you choose to look at it, this means -11 > 0 (regardless of all arguments concerning implicit conversions, 1's and 2's complements, being efficient, etc).
> 
> The language should not allow unary unsigned anything.
> 

I have no idea what your use case is for this but...
WHY are you doing this??

If you declared charlie as unsigned, why would you then attempt to
compare using a negative value?  If you even had the possibility that
charlie might be negative, why wouldn't you use a type that can accomodate the sign?

Using the proper type, you get a proper result:

        long b = 12;
        long n = std.algorithm.comparison.max(0, -b);
        long o = std.algorithm.comparison.max(0, b);
        writeln("n: ", n);              // prints 0
        writeln("o: ", o);              // prints 12

Seems obvious to me, but am I missing something?

scot
January 22, 2024

On Sunday, 21 January 2024 at 16:05:40 UTC, Gavin Gray wrote:

>

The following code:

ulong charlie = 11;
long johnstone = std.algorithm.comparison.max(0, -charlie);
writeln(format!"johnstone %s"(johnstone));

Results in (without any warning(s)):
johnstone -11

However you choose to look at it, this means -11 > 0 (regardless of all arguments concerning implicit conversions, 1's and 2's complements, being efficient, etc).

The language should not allow unary unsigned anything.

This returns -1:

import std;

void main() {
    ulong charlie = 11;
    long johnstone = std.algorithm.comparison.max(0, -charlie);
    writeln(format!"johnstone %s"(johnstone));
}

If you change the result type to auto johnstone, it returns 18446744073709551605:

module app;

import std;

void main() {
    ulong charlie = 11;
    auto johnstone = std.algorithm.comparison.max(0, -charlie);
    writeln(format!"johnstone %s"(johnstone));
}

So what happens is, max() correctly returns 18446744073709551605,
but if you explicitely receive a long, the ulong is converted to a long,
resulting in -11.

With auto johnstone or ulong johnstone the result is correct:

import std;

void main() {
    ulong charlie = 11;
    ulong johnstone = std.algorithm.comparison.max(0, -charlie);
    writeln(format!"johnstone %s"(johnstone));
}

If you take a bigger type, like Int128, it is also correct:

import std;

void main() {
    ulong charlie = 11;
    Int128 johnstone = std.algorithm.comparison.max(0, -charlie);
    writeln(format!"johnstone %s"(johnstone));
}
January 22, 2024
On Monday, 22 January 2024 at 06:43:17 UTC, thinkunix wrote:
> Gavin Gray via Digitalmars-d-learn wrote:
>> The following code:
>> 
>>    ulong charlie = 11;
>>    long johnstone = std.algorithm.comparison.max(0, -charlie);
>>    writeln(format!"johnstone %s"(johnstone));
>> 
>> Results in (without any warning(s)):
>> johnstone -11
>> 
>> However you choose to look at it, this means -11 > 0 (regardless of all arguments concerning implicit conversions, 1's and 2's complements, being efficient, etc).
>> 
>> The language should not allow unary unsigned anything.
>> 
>
> I have no idea what your use case is for this but...
> WHY are you doing this??
>
> If you declared charlie as unsigned, why would you then attempt to
> compare using a negative value?  If you even had the possibility that
> charlie might be negative, why wouldn't you use a type that can accomodate the sign?

I'm sure they would if the compiler had stopped and provided an error message to tell them what they were doing. Note that in this line

```
long johnstone = std.algorithm.comparison.max(0, -charlie);
```

there is no direct assignment of a negative number to an unsigned type. The comparison is carried out as ulong and then there's an implicit conversion of a ulong to long, even though that can give a very weird result. It's perfectly natural to expect that everything will be carried out as a long since that's what's specified, or that a language like D will forbid implicit conversions if they can possibly give the wrong answer. If you change the long to int, the code will no longer compile.

Aside from the general statement that programmers make mistakes, D is prone to these issues because of the heavy use of auto, and because unsigned types are used for things like the length of an array.
January 22, 2024

On Monday, 22 January 2024 at 03:53:54 UTC, bachmeier wrote:

>

There needs to be a safe arithmetic mode because the current behavior of double j = 10 / 3; is not what anyone expects and is a bug 100% of the time.

Don has a solution:
https://issues.dlang.org/show_bug.cgi?id=12452

>

I've said multiple times that it's silly to spend so much time on memory safety if the language is going to allow stuff like this without a simple way to prevent it.

Memory safety issues are a worse class of bug than arithmetic bugs. The latter are reproducible if you feed them the same input.

January 22, 2024

On Monday, 22 January 2024 at 01:14:06 UTC, Steven Schveighoffer wrote:

> >

The language should not allow unary unsigned anything.

This is unlikely to get fixed, just due to the nature of D's philosophy when it comes to C compatibility.

It would also break a lot of existing code.

I think the bigger issue is implicit conversion from unsigned to signed of the same bit size. In a future edition D could require a larger signed type in order to implicitly convert from unsigned. That would have caught the long johnstone = line.

Also signed should never convert to unsigned, though I don't think that's happening here.

January 22, 2024

On Monday, 22 January 2024 at 16:39:10 UTC, Nick Treleaven wrote:

> >

I've said multiple times that it's silly to spend so much time on memory safety if the language is going to allow stuff like this without a simple way to prevent it.

Memory safety issues are a worse class of bug than arithmetic bugs.

The required language changes are pretty small to catch arithmetic bugs relative to implementing memory safety. Ultimately, you want the compiler to help you catch bugs in any form, and I don't think someone that wants memory safety is likely to be okay with the type of bugs in this thread.

But for me, arithmetic bugs are a much larger problem than memory safety. I mostly use the GC plus calls into well-tested C libraries. I get incorrect results, and when I'm lucky, my program segfaults because I accessed something I shouldn't. When I'm not, it silently and happily gives me the wrong answer.

January 22, 2024

On Monday, 22 January 2024 at 16:39:10 UTC, Nick Treleaven wrote:

>

Memory safety issues are a worse class of bug than arithmetic bugs. The latter are reproducible if you feed them the same input.

Memory safety bugs are reproducible with the tools like valgrind. Whereas arithmetic overflow bugs are a real PITA to debug. Assuming that the incorrect results are even noticed.

« First   ‹ Prev
1 2 3