Description
What is this
This is a design document for const generics. Any discussions about its content should be on zulip. The conclusions of these discussions should then be edited back into this issue. Please do not post any comments directly in this issue.
Content
It would be nice to allow function pointers as const parameter types.
struct WithFunc<const GET: fn() -> usize>;
impl<const GET: fn() -> usize> WithFunc<GET> {
fn get(self) -> usize {
GET()
}
}
fn foo<const GET: fn() -> usize>() -> usize {
GET()
}
fn getter() -> usize { 3 }
fn main() {
let x: WithFunc<{ getter }> = WithFunc;
assert_eq!(x.get(), foo::<{ getter }>();
}
While they do have a sensible definition of structural equality at compile time,
comparing them is not deterministic at runtime. This behavior might be fairly surprising,
so it might be better to not allow this.
Two function pointers considered equal at compile time can end up not being equal at runtime, as the function ends up getting monomorphized in two different CGUs.
Two function pointers which are different at compile time can end up being equal at runtime,
as the functions can get deduplicated if their behavior is equivalent.
Alternatives
Use type parameters with trait bounds instead.
struct WithFunc<F: FnOnce() -> usize> { get: F };
fn foo<F: FnOnce() -> usize>(get: F) -> usize {
get()
}
fn getter() -> usize { 3 }
type Getter = impl FnOnce() -> usize;
fn mk_with_func() -> WithFunc<Getter> {
WithFunc {
get: getter,
}
}
fn main() {
// Using a type alias, we have to constrain it in some function,
// might not always be nice to use.
let x: WithFunc<Getter> = mk_with_func();
// Adding a way to name function types.
let y: WithFunc<fn::getter> = WithFunc { get: getter };
assert_eq!(x.get(), y.get());
assert_eq!(x.get(), foo(getter));
}
This requires us to also add a ZST as an input to all functions, or add some Default
bound.
If we ever get generic const parameter types (#28), the following would also be an option:
struct WithFunc<F: FnOnce() -> usize, const GET: F>;
impl<F: FnOnce() -> usize, const GET: F> WithFunc<F, GET> {
fn get(self) -> usize {
GET()
}
}
fn foo<F: FnOnce() -> usize, const GET: F>() -> usize { GET() }
fn main() {
let x: WithFunc<_, { getter }> = WithFunc;
assert_eq!(x.get(), foo::<_, { getter }>());
}
Note that this still requires us to name the function type if we want to use the const parameter inside of a type definition or item signature.
Previous discussions
Dependencies
- blocked on Structural equality #29