Most of the work I do in systems programming languages is bare-metal code where semantics for representing and manipulating data at the bit-level are required. I need to have very explicit control over the shape of the data in memory. For starters, many of the systems I work with don't even have the ability to do floating-point calculations at all.
> "Compilers (and type systems) are written by and for humans..."
The abstraction that is the type system might be designed for humans, but the underlying physical layers are totally non-abstract, tangible things with their own constraints. If I'm sending data to a DAC over the i2c protocol, the protocol has very real constraints at the electrical level. In order to interact with such protocols in a meaningful way we need low-level semantics to control the shape of data at the level of individual bits.
Consider the following:
uint32_t a = 1234567;
float b = 0.34;
uint8_t c = a * b;
fwrite(&c, 1, 1, stream);
What value gets written to the stream here?
> "first tell me the use case for multiplying a float by an int that does not lead to a float"
Should the Rust compiler forbid all multiplication between the two types that doesn't get stored in a float?
One can manipulate arbitrary precision integers at the bit level. Nonnegative integers correspond to infinite sequences of bits all but a finite number of which are 0; negative numbers to infinite sequences in which all but a finite number are 1. There's no need in most programs to insist that variables have some finite (and fairly small) range beyond which integer operations stop acting like their mathematical definition.
There are very real use cases where integer types with specific fixed widths are necessary, on account of very real constraints. A serial interface for instance, which is a very common peripheral outside of PCs, often sends information out over the wire 8 bits at a time. 'Systems programming languages' need to specify how arithmetic using these fixed-width integers should work.
> "Compilers (and type systems) are written by and for humans..."
The abstraction that is the type system might be designed for humans, but the underlying physical layers are totally non-abstract, tangible things with their own constraints. If I'm sending data to a DAC over the i2c protocol, the protocol has very real constraints at the electrical level. In order to interact with such protocols in a meaningful way we need low-level semantics to control the shape of data at the level of individual bits.
Consider the following:
What value gets written to the stream here?> "first tell me the use case for multiplying a float by an int that does not lead to a float"
Should the Rust compiler forbid all multiplication between the two types that doesn't get stored in a float?