Skip to content

Functions as const parameters #27

Open
@lcnr

Description

@lcnr

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-param-typesConst parameter typesC-design-docsCategory: This is part of our design documentationK-behaviorDocument Kind: regarding user visible behaviorP-optionalPriority: not strictly requiredS-blocked

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions