make functions `const` where possible
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`.
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.
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
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
I will add to the One::one() example, that any attempt to add const, will be incompatible with BigInt, as they have heap allocated data. On the other hand, have you looked at the optimized assembly? Afaict the compiler realizes what it can precompute pretty well. Maybe no trigonometric functions, but still, the simpler usecases are covered by compiler optimization afaict. If you need constants with a simple Complex64 computed in some complicated way, just compute it yourself, insert the number directly into the code and make a comment where it came from. IMO, this issue can be closed (hope that is not rude to say)
e.g. even something simple like
const fn i()would need constZeroandOne.
We do have some associated consts now, since #125!
And rust-num/num-bigint#307 could even let those do ONE and I.
But since almost everything else will require const traits, I do think we can close this for now.