rust-num / num-complex

Complex numbers for Rust
Apache License 2.0
232 stars 50 forks source link

make functions `const` where possible #117

Open rursprung opened 11 months ago

rursprung commented 11 months ago

as the title says: it'd be great if as many functions as possible were made const so that they can be used in a const environment.

currently this code will not compile because the Add implementation of Complex isn't const:

use num::complex::Complex32;

const X: Complex32 = Complex32::new(1., 0.);
const Y: Complex32 = Complex32::new(0., 1.);
const Z: Complex32 = X + Y;

you can find the same example on the playground.

error from the playground:

   Compiling playground v0.0.1 (/playground)
error[E0015]: cannot call non-const operator in constants
   --> src/main.rs:6:26
    |
6   |     const Z: Complex32 = X + Y;
    |                          ^^^^^
    |
note: impl defined here, but it is not `const`
   --> /playground/.cargo/registry/src/index.crates.io-6f17d22bba15001f/num-complex-0.4.4/src/lib.rs:724:1
    |
724 | impl<T: Clone + Num> Add<Complex<T>> for Complex<T> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants

For more information about this error, try `rustc --explain E0015`.
cuviper commented 11 months ago

Rust as a language doesn't have const trait implementations yet, so we don't have any way to make stuff like operator + const. Most of the inherent methods of Complex also depend on trait bounds, so they can't be const yet either -- e.g. even something simple like const fn i() would need const Zero and One.

rursprung commented 11 months ago

oh, sorry, i didn't even realise that! i just looked around a bit and it seems that it'll need this nightly feature to be stabilised: https://github.com/rust-lang/rust/issues/67792 once that's done it should be possible to make these implementations const

cuviper commented 11 months ago

For simple stuff like Add, at least it's not too bad to do it manually:

const X: Complex32 = Complex32::new(1., 0.);
const Y: Complex32 = Complex32::new(0., 1.);
const Z: Complex32 = Complex32::new(X.re + Y.re, X.im + Y.im);

But of course this would be a pain for more complex expressions. (pun intended :smile:)

If you have a lot of constant values like this that you want to prepare, you could also do it in a build.rs script to write a generated source file, as described in the Cargo book: https://doc.rust-lang.org/cargo/reference/build-script-examples.html#code-generation