Providing implicit conversion of - memory-safety

Renato renato at athaydes.com
Wed Jan 24 09:28:57 UTC 2024


On Wednesday, 24 January 2024 at 00:34:19 UTC, bachmeier wrote:
> On Tuesday, 23 January 2024 at 21:40:46 UTC, Renato wrote:
>
>> While I can understand your frustration, it seems to me D is 
>> not to blame in this instance because the code is quite 
>> patently using unsafe constructs (D does not claim to be fully 
>> safe).
>
> It pretends to be safe. Consider this:
>
> ```
> void main() {
>     long y = int.max + 1;
>     writeln(y);  // -2147483648
>     long y2 = int.max;
>     writeln(y2 + 1); // 2147483648
>     int y3 = y; // Won't compile
> }
> ```
>
> It can only be described as a mess of inconsistency. `int y3 = 
> y;` should be an error and it is. `int.max + 1` silently 
> turning into a negative value is frankly insane because it's 
> the same problem that a few lines below won't compile.
>
>> Would something like this work?
>>
>> ```d
>> double value(T)(T index, double* x) if (is(T : size_t))
>> ```
>
> There's no way to add a template constraint. Many different 
> types, most of which I defined myself, could be sent as an 
> argument.
>
>> that it's almost always a mistake to subract from any unsigned 
>> type - D scanner correctly warns about that).
>
> It's the inconsistency that's the problem. You have to program 
> as if the compiler doesn't catch anything - sometimes it throws 
> errors, sometimes it lets stuff through because maybe that's 
> what you want. `int y3 = y` in the code above is not 
> necessarily an error.

For the record, even Rust allows you to subtract from an unsigned 
type, but it warns you about it and it fails at runtime due to 
the subtraction overflowing (which I believe Rust only checks in 
debug mode - in release mode I believe it would behave like D 
does in this case, but I didn't verify that).

Here's an example program that compiles:

```rust

fn action(n: usize, arr: &[i64]) -> i64 {
     if n - 5 < 0 {
         0
     } else {
         arr[n - 5]
     }
}

fn main() {
     let arr: [i64; 6] = [1,2,3,4,5,6];
     println!("{}", action(4, &arr));
}
```

Compiling and running it:

```rust
warning: comparison is useless due to type limits
  --> src/main.rs:3:8
   |
3 |     if n - 5 < 0 {
   |        ^^^^^^^^^
   |
   = note: `#[warn(unused_comparisons)]` on by default

warning: `playground` (bin "playground") generated 1 warning
     Finished dev [unoptimized + debuginfo] target(s) in 0.49s
      Running `target/debug/playground`
thread 'main' panicked at src/main.rs:3:8:
attempt to subtract with overflow
note: run with `RUST_BACKTRACE=1` environment variable to display 
a backtrace
```

I believe that DScanner also warns about the OP's code (I see 
this warning all the time in my D code)... but again, if you want 
to subtract a number from an unsigned typed variable, you should 
absolutely check first that variable is `>=` that number, in Rust 
or D or any other language.

If you have "widespread" arithmetics which may overflow, 
something like https://dlang.org/phobos/core_checkedint.html is 
useful, yes, but in this case it's overkill.

Some languages, like Pony, have dedicated operators for "safe 
arithmetics" (because they're much slower and are only rarely 
strictly needed):


```
// unsigned wrap-around on overflow
U32.max_value() + 1 == 0

// unsafe operator (undefined behaviour, like with C operators)
U32.max_value() +~ 1 // could be anything!

// safe operator (throws on overflow)
U32.max_value() +? 1
```



More information about the Digitalmars-d-learn mailing list