Proposal
Problem statement
I am writing a virtual machine for a virtual assembly language which allows different sized registers, that means it supports many different widths of integers and floats, such as u11, u32, u64, f32, f64.
Obviously, emulating u32 is easy, whereas u11 needs much more complicated logic.
I special case these using match statements so I need to have constants and ideally these should be short and obviously correct.
Another potential use case is when reading from a binary file, but I haven't personally needed these constants then, so I won't discuss them here.
Motivating examples or use cases
For integers this comes out cleanly as:
match width {
u32::BITS => compute<u32>() // Arithmetic using u32s
u64::BITS => compute<u64>() // Arithmetic using u64s
_ => {} // Arbitrary precision
However for floats I currently have
match width {
32 => compute<f32>() // Arithmetic using f32s
64 => compute<f64>() // Arithmetic using f64s
_ => {} // Arbitrary precision floats
}
Additionally to store these effectively I have special data structures for these primitives, which looks roughly like:
fn store(width: u32, index: u32, val: f32) {
assert_eq!(width == 32)
}
It would be nice if here I could assert (as I do with u32, u64, i32, i64):
assert_eq!(width == f32::BITS)
This shows intent much more clearly.
Solution sketch
Add f32::BITS and f64::BITS constants:
impl f32 {
pub const BITS: u32 = 32;
}
impl f64 {
pub const BITS: u32 = 64;
}
u32 is already used as the type for BITS for signed and unsigned primitives, so we should keep it the same.
This brings f32 and f64 in line with other primitives: u8, u32, u64, i8, i32, i64.
The documentation for f32 specifically defines it as a A 32-bit floating-point type - this just introduces a constant for it.
Additionally, to_le_bytes, is already defined as returning [u8; 4] so the size is already well-specified.
https://doc.rust-lang.org/std/primitive.u32.html#associatedconstant.BITS
Alternatives
Of course, a user constant could easily be defined as F32_BITS but this would have to be imported in every file and not be as clear.
They could also define a trait and bring it into scope that defined these constants.
Additionally, for some use-cases, using size_of<T>() might be sufficient, however this does not work for my use case since it can't be used in a match expression and returns something of type usize instead of u32, which doesn't match u32::BITS.
Additionally, I understand size_of more as how much memory space is used not an indication of "precision":
More specifically, this is the offset in bytes between successive elements in an array with that item type including alignment padding. Thus, for any type T and length n, [T; n] has a size of n * size_of::() - https://doc.rust-lang.org/std/mem/fn.size_of.html
In a hypothetical case where there was a f4 introduced, size_of would give 1 byte due to padding.
Obviously I understand this is low-hanging fruit, but it would be nice to have a more uniform API between floats and integers.
Links and related work
Java defines a BYTES constant for floats and doubles:
What happens now?
This issue contains an API change proposal (or ACP) and is part of the libs-api team feature lifecycle. Once this issue is filed, the libs-api team will review open proposals as capability becomes available. Current response times do not have a clear estimate, but may be up to several months.
Possible responses
The libs team may respond in various different ways. First, the team will consider the problem (this doesn't require any concrete solution or alternatives to have been proposed):
- We think this problem seems worth solving, and the standard library might be the right place to solve it.
- We think that this probably doesn't belong in the standard library.
Second, if there's a concrete solution:
- We think this specific solution looks roughly right, approved, you or someone else should implement this. (Further review will still happen on the subsequent implementation PR.)
- We're not sure this is the right solution, and the alternatives or other materials don't give us enough information to be sure about that. Here are some questions we have that aren't answered, or rough ideas about alternatives we'd want to see discussed.
Proposal
Problem statement
I am writing a virtual machine for a virtual assembly language which allows different sized registers, that means it supports many different widths of integers and floats, such as
u11,u32,u64,f32,f64.Obviously, emulating
u32is easy, whereasu11needs much more complicated logic.I special case these using match statements so I need to have constants and ideally these should be short and obviously correct.
Another potential use case is when reading from a binary file, but I haven't personally needed these constants then, so I won't discuss them here.
Motivating examples or use cases
For integers this comes out cleanly as:
However for floats I currently have
Additionally to store these effectively I have special data structures for these primitives, which looks roughly like:
It would be nice if here I could assert (as I do with u32, u64, i32, i64):
This shows intent much more clearly.
Solution sketch
Add
f32::BITSandf64::BITSconstants:u32is already used as the type forBITSfor signed and unsigned primitives, so we should keep it the same.This brings f32 and f64 in line with other primitives: u8, u32, u64, i8, i32, i64.
The documentation for f32 specifically defines it as a
A 32-bit floating-point type- this just introduces a constant for it.Additionally, to_le_bytes, is already defined as returning
[u8; 4]so the size is already well-specified.https://doc.rust-lang.org/std/primitive.u32.html#associatedconstant.BITS
Alternatives
Of course, a user constant could easily be defined as
F32_BITSbut this would have to be imported in every file and not be as clear.They could also define a trait and bring it into scope that defined these constants.
Additionally, for some use-cases, using
size_of<T>()might be sufficient, however this does not work for my use case since it can't be used in a match expression and returns something of typeusizeinstead ofu32, which doesn't matchu32::BITS.Additionally, I understand
size_ofmore as how much memory space is used not an indication of "precision":In a hypothetical case where there was a
f4introduced,size_ofwould give 1 byte due to padding.Obviously I understand this is low-hanging fruit, but it would be nice to have a more uniform API between floats and integers.
Links and related work
Java defines a
BYTESconstant for floats and doubles:What happens now?
This issue contains an API change proposal (or ACP) and is part of the libs-api team feature lifecycle. Once this issue is filed, the libs-api team will review open proposals as capability becomes available. Current response times do not have a clear estimate, but may be up to several months.
Possible responses
The libs team may respond in various different ways. First, the team will consider the problem (this doesn't require any concrete solution or alternatives to have been proposed):
Second, if there's a concrete solution: