rust-lang / rfcs

RFCs for changes to Rust
https://rust-lang.github.io/rfcs/
Apache License 2.0
5.96k stars 1.57k forks source link

Generic consts #2424

Open SoniEx2 opened 6 years ago

SoniEx2 commented 6 years ago

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 6 years ago

How does this differ from const fn?

SoniEx2 commented 6 years ago

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)

clarfonthey commented 6 years ago

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.

alexchandel commented 6 years ago

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)

steveklabnik commented 6 years ago

Are you asking for something different than RFC 2000?

On Oct 16, 2018, at 2:03 PM, Alex notifications@github.com wrote:

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)

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or mute the thread.

emanuelpalm commented 5 years ago

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?

SoniEx2 commented 5 years ago

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

emanuelpalm commented 5 years ago

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

zesterer commented 5 years ago

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.