This is idiomatic use of const
(i.e. giving a name to a constant value) and what you're describing sounds like static
(i.e. placing a constant value in a static memory location).
I don't think it's idiomatic to use const
'as much as possible' within functions; I mean, there are use cases for it, but it sounded like @johnthagen wanted to use it in cases where let
would be more idiomatic.
And yeah, I didn't want to complicate things further with const
versus static
, since usually the behavior is the same.
Oops, I hadnât seen the actual reasoning for using const
, which AFAIK is invalid, I agree with you there.
Yes, your intuition was correct. It's something I've been struggling to figure out how to do correctly and consistently. The only definitive response I had gotten up to this point was
My rationale was wanting to default to the most restrictive type possible (similar to defaulting to immutable bindings), so it was a sort of "static by default". But for all of the reasons you've pointed out, I am going to stop doing that.
Would this be a good summary for the idiomatic rules for const
?
- Use for immutable constants whose scope is larger than a function.
- Use for large-sized* immutable constants declared within functions.
Where large-sized means a type takes significantly larger memory storage than an integer/pointer type.
IMO an IntegerLiteral
trait would be nice.
It means you can do this to emulate âconstantsâ:
fn universal_constant<I: IntegerLiteral>() -> I { 42 }
Could also replace fn
with const fn
too.
Wouldnât some kind of âuntyped numberâ (<- const only) type be a alternative solution?
e.g. const FOO: UntypedNumber = 123456;
Where the constant FOO is interpreted dependent on itâs context. And a error(warning?) is thrown if the given typed number does not fit into the given numeric type.
Wrt. to backward compatibility and name collision UntypedNumber
would be type in std marked with #[lang_item="untyped_number"]
(also it should be zero sized with a single private zero sized field to prevent usage elsewhere, maybe also warning if used in generics etc.).
Not that I intentionally used ânumberâ not integer, there is no reason to limit this functionally to integers e.g. let x: f32 = FOO;
should then be equivilant to let x: f32 = 123456f32
and FOO could aso be const FOO: UntypedNumber = 12.4;
making it usable with f32
/f64
and possible other native number types if they are added to rust.
Additionally std might provide a simple (const) fn to hint the type (as
is not enough as as
would also be used for casting. E.g. let x = FOO as u8;
is ambiguous between Error 1234 does not fit into u8
and 1234<?> as u8
, defaulting to the former one would be unnecessary error prone. Basically a (#[inline(always)] const) fn typed<T>(x: T) -> T { x }
(not the ( .. )
is because Iâm not sure about #[inline(always)]
and const
is not stable, also the combination of both makes little sense )
TL;DR:
in (e.g.) std/const/lib.rs
#[lang_item = "untyped_number" ]
pub struct UntypedNumber {
_no_construction: ()
}
pub const fn typed<T>(x: T) { x }
in example
use std::const::{UntypedNumber, typed};
const FOO: UntypedNumber = 1234;
const BAR: UntypedNumber =12.4; //ok, through works only with f32/f64 etc.
fn main() {
// for simplicity I will only use `let var =` and `let var: type =` state ments
// for all cases where the type of `var` is unknown and know through other
// means respectively
let a: u32 = FOO; //FOO equiv. 1234u32
let b: f32 = FOO; //FOO equiv. 1234f32
let c = typed::<f32>(FOO); //equiv. to `typed::<f32>(1234f32)`
let a = FOO; //error can't resolve type
let a: u8 = FOO; //error u8 can only contain numbers in range [0;255] got 1234
let a = FOO as u8; //error can't resolve type, abiguity between typing and casting
let a = FOO as u32; //aslo? error can't resolve type, abiguity between typing and casting or not??
let a = typed::<u32>(FOO) as u8; //equiv. to `1234u32 as u8`
}
not that typed
is no âmagicâ at all just a (additional) way to hint the type to the compiler (itâs not necessary needed, if it is wanted I do not know).
Note that currently typed::<f32>(12)
does not compile as 12 is a {integer}
. Through it would be fine with FOO as, given the type hint of T=f32, FOO would be equivalent to â1234 f32â, and not just â1234â.
Question 1: is there any non number usage for âuntypedâ constants
Question 2: is there any case where a typed::<...>(FOO)
should not error if the number does not fit into the type (e.g. warn instead and use as ...
). Also wrt. float
we would have to take the closest actual representable number (else 0.1 wonât work),
but when(if at all) do/should we error/warn that f32âs precision is to low for given number?
EDIT: I just noticed that I only read from @retep998 post (nr. 14, 6.3.2017) onward and a similar Idea had already been mentioned.
PS:
I just noticed that I posted on this thread before, and that my opinion has slightly changed since then.
I no longer believe that something like const x = 1234;
as it would mess with type interference for constants (like mentioned by @tbu before).
Also I wrote before that a literal types can have some problems in combination with literals/numbers as type-parameters (e.g. <n:UINT> for a Array type). I do no longer believe this. In the worst case the usage as generic parameter could simple be forbidden for a type tagged with lang_item="untyped_number"
.
Nevertheless this depends on how literals as type-parameters are implemented, if they are limited to specific types (uXX, &'static str??) this is no problem anyway. In that case UntypedNumber can be resolved as such type (with all the âerror casesâ seen before e.g. number canât be represented with given precision).
If âgeneralâ const values (inclusive const structs) can be used it is a bit more tricky,
but still would be fine with the rules for resolving FOOâs type indirectly mentioned above. Basically what I proposed in previous post can be seen very similar to using a macro/text replacement, expect that the ârightâ suffix (e.g. f32 in 1f32) is added to the expanded number. Which should resolve any question about ambiguity and casting in a future prove way (<- I think but might be wrong ) .
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.