Rust compile-time expression evaluation and const objects

To what extent does Rust support compile-time expression evaluation and const or static array allocation? And, does the Rust compiler/linker allocate const or static objects in read-only code pages for environments which support them?

In particular, what does Rust do with code like:

const I32_FACTORIALS: [i32; 13] =
[
    1,
    1,
    1 * 2,
    1 * 2 * 3,
    1 * 2 * 3 * 4,
    1 * 2 * 3 * 4 * 5,
    1 * 2 * 3 * 4 * 5 * 6,
    1 * 2 * 3 * 4 * 5 * 6 * 7,
    1 * 2 * 3 * 4 * 5 * 6 * 7 * 8,
    1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9,
    1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10,
    1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11,
    1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12
];

For a working toy example, see:

https://replit.com/@QuantMethods/Factorial

Bonus question: Why must an explicit size be provided for the array type? If omitted, the compiler will helpfully provide the correct value in the error message, but will not use the value itself. I see that a previous RFC on this subject has been closed with a status of "postponed" after over two years of consideration. However, it is not clear why "postponed" rather than accepted or rejected or how "postponed" items are tracked until their time has come...

It won't do anything with just a const because it's not used anywhere.

const items looks remarkably similar to static items, which introduces some confusion as to which one should be used at which times. To put it simply, constants are inlined wherever they’re used, making using them identical to simply replacing the name of the const with its value. Static variables, on the other hand, point to a single location in memory, which all accesses share. This means that, unlike with constants, they can’t have destructors, and act as a single value across the entire codebase.

Sometimes a local read-only array might be promoted to be static, but I don't think there's any guarantee of such. If you don't want it on the stack, put it in a static.

Here's the part of the reference that talks about compile time (const) evaluation. And for statics.

Statics generally go in .rodata (for ELF) but I don't know if this is a guaranteed default per se. You can override it apparently.


I don't know any reasons beyond the last few comments in the PR.

You can use &[i32] instead, but this may result in more indirection or bounds checks.

Why shouldn't it? Statics and consts (just like function signatures) must be explicitly typed, and the size is part of the type for an array.

The code fragment posted does not use I32_FACTORIALS, but the toy example for which I provided a link does. However, your response seems to say that each use of the const array would be expanded inline rather than referencing a single const array in memory. Not sure that is what happens with const arrays, but that is really my own ignorance.

So, to declare a single array of constant values accessed within a single file/module, do I just declare it as static or static const or something like C started to require when the const keyword was added? Something like:

static const int* const INT_FACTORIALS = [ 1, 1, 2, ... ];

And no, I know that is invalid C, but I am just trying to understand the interplay of static, const, and arrays when trying to create lookup tables initialized at compile-time.

Edit: Is static always "const"/immutable? I would think so. In which case, the complicated C-like syntax I suggested is not an issue. However, is "static mut" a thing?

Just declare it as a static.

Well, I can leave out the "type" and rely on type inferencing. Or, at least I can with let within a function definition. But then I need to specify the type of the integer literals used to initialize the array. A single 1i32 did not work for me nor did adding "as i32" after the first integer literal in each initializer expression. (Though, when I tried that, I believe it was still while trying to declare a const or static array where a type is demanded by the compiler rather then a let variable...)

So, when creating sizable lookup tables, the programmer must ensure they correctly count the number of elements when defining the array and any time the array is edited in the future. Not a terrible problem, because the compiler will report the correct value when the "type" has not been correctly updated, but it seems to be needlessly tedious syntax and friction.

But you can't rely on inference in top-level items such as functions and traits. Consts and statics are the same kind of globally accessible item, so it's consistent that they enforce fully explicit typing.

Then again, you can declare the LUT as a slice and you won't need to include the length.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.