0

I would like to allocate an SVector<f64, 7> as a static variable. It seems that nalgebra's library-provided builders cannot do this, as none of them are const. Is there a workaround?

Here's what I tried (this doesn't compile):

const C5: SVector<f64, 7> = SVector::<f64, 7>::from_row_slice(&[
  5179.0 / 57600.0,
  0.0,
  7571.0 / 16695.0,
  393.0 / 640.0,
  -92097.0 / 339200.0,
  187.0 / 2100.0,
  1.0 / 40.0,
]);

Edit: As @kmdreko pointed out, the following questions were more appropriate for a separate post: Why can't Rust use non-const-qualified functions to allocate const variables? Why does it matter whether or not a function is const if the data it's operating on is const?

mcmuffin6o
  • 348
  • 1
  • 9
  • 1
    You're asking a lot of questions but you should probably condense it to either focusing on the practical part with `SVector` or the theoretical parts. That would make your post more appropriate for StackOverflow. – kmdreko Aug 13 '23 at 01:23
  • 2
    The workaround is to do lazy initialization (not const initialization) with something like the lazy-static crate or its more in-style to use [`Lazy`](https://docs.rs/once_cell/latest/once_cell/sync/struct.Lazy.html) from the once-cell crate. – kmdreko Aug 13 '23 at 01:24
  • Sorry for the barrage of questions! I'll see about making another post for the more theoretical ones. – mcmuffin6o Aug 13 '23 at 20:02

1 Answers1

3

I found a const constructor: from_array_storage.

use nalgebra::{ArrayStorage, SVector};

const C5: SVector<f64, 7> = SVector::<f64, 7>::from_array_storage(ArrayStorage([[
    5179.0 / 57600.0,
    0.0,
    7571.0 / 16695.0,
    393.0 / 640.0,
    -92097.0 / 339200.0,
    187.0 / 2100.0,
    1.0 / 40.0,
]]));

For your other questions:

  • Rust has both const and static values. If you need a global value that can't be constructed at compile time, then you can use a static, usually with something like Lazy (LazyLock in future Rust standard library), or thread_local.
  • Rust does not have the ability to promote a non-const function to const. If it could, then a change to the internals of a function could be a breaking change. However, Rust will evaluate let and static bindings at compile time if it is able and decides it is beneficial for optimization.
  • Just because the parameters are const does not mean that all the operations inside a function are const. Usually this is allocation.
drewtato
  • 6,783
  • 1
  • 12
  • 17
  • Thanks for the incredibly helpful answer! How does the "constructor" for `ArrayStorage` work? It almost makes sense, but I haven't seen anything like it in The Book... or perhaps it's a [tuple struct](https://doc.rust-lang.org/stable/book/ch05-01-defining-structs.html#using-tuple-structs-without-named-fields-to-create-different-types) with a single member? I'm also confused as to why there's two sets of square brackets. – mcmuffin6o Aug 13 '23 at 20:24
  • Oops! [It is indeed a tuple struct, as indicated by this section that was staring me in the face](https://docs.rs/nalgebra/latest/nalgebra/base/struct.ArrayStorage.html#fields). It appears that the reason there are two sets of square brackets is that it stores the data in column-major order such that each array within the outer brackets contains a column of data. – mcmuffin6o Aug 13 '23 at 20:36
  • 1
    Yeah, the double brackets was just to make this compile with the type you specified, which uses `ArrayStorage`. It could be that you wanted `ArrayStorage`, but that's no longer `SVector`. – drewtato Aug 13 '23 at 20:47