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?
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:
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:
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