rust-lang/rfcs

Generic consts

Opened this issue · 9 comments

Not to be confused with const generics, but I'll use both to describe the idea.

Let's say you have a const initializer and you want it to be different for every type:

const NONE_T_8ARRAY<T>: [Option<T>; 8] = [None; 8];

This is the basic generic const construct. Ofc, if you want length also specified:

const NONE_T_ARRAY<T, const L: usize>: [Option<T>; L] = [None; L];

This creates an array of size L containing only None.

Ofc, you also don't need to use types, consts are fine too:

const SQUARE<const X: usize>: usize = X * X;

But perhaps you want it to be recursive:

const POW<const X: usize, 0>: usize = 1;
const POW<const X: usize, const Y: usize>: usize = X * POW<X, Y-1>;

And you want to calculate Pi with it [1]:

const POW<const X: usize, 0>: usize = 1;
const POW<const X: usize, const Y: usize>: usize = X * POW<X, Y-1>;
const PI<-1>: f64 = 0;
const PI<const N: isize>: f64 = (1.0/POW<16, N as usize> * (4.0/(8*N + 1.0) - 2.0/(8*N + 4.0) - 1.0/(8*N + 5.0) - 1.0/(8*N + 6.0))) + PI<N-1>;

And things of the sort.

Yeah... they'd be nice.

May we have them?

CryZe commented

How does this differ from const fn?

And if you want to use it in a runtime context, altho the types have to be evaluated at compile-time, you can use use x:

const POW<const X: usize, 0>: usize = 1;
const POW<const X: usize, const Y: usize>: usize = X * POW<X, Y-1>;

fn do_something(x: usize, y: usize) -> usize {
    POW<use x, use y>
}

It's not different from const fn - it replaces const fn. The ability to use like that makes const vs non-const explicit:

fn do_something(x: usize) -> usize {
    POW<use x, 3> // expands/unrolls to x*x*x. this is inherently more flexible than const fn.
}

fn do_something_else(x: usize) -> usize {
    POW<use x, use 3> // recurses at runtime (may be unrolled by LLVM tho)
}

(Altho the idea of use x is controversial so I didn't put it in the main issue body thing or w/e it's called)

I do think that the ability to coerce literals into multiple types without macros would be very useful. Not sure if this is the answer, though.

This doesn't replace the "type level integers" portion of #1038, so there are currently no RFCs for type level integers, right? (beyond the existing ways to hack them in)

I would like to have this in order to be able to return a static array with the same number of arguments as was provided in a static input array, like so:

fn do_something<N>(elements: [isize; N]) -> [usize; N] {
  // Implement, somehow ...
}

Is that something you would be able to do with const fns?

@emanuelpalm that's const generics (consts in generics i.e. <const FOO: T>), not generic consts (consts with generics i.e. const FOO<T>)

@SoniEx2 Oh. True. I came here via some other issue, and I guess I didn't read the description properly. :P

Here:

const POW<const X: usize, 0>: usize = 1;
const POW<const X: usize, const Y: usize>: usize = X * POW<X, Y-1>;

fn do_something(x: usize, y: usize) -> usize {
    POW<use x, use y>
}

You seem to be coercing a value known only at runtime into a const value. This simply isn't possible since Rust doesn't support that sort of runtime reflection capability once compiled.