# Pre-RFC: FnStatic

**URL:** <https://internals.rust-lang.org/t/pre-rfc-fnstatic/22571>\
**Category:** language design\
**Created:** [March 15, 2025, 4:21pm UTC](https://internals.rust-lang.org/t/pre-rfc-fnstatic/22571 "2025-03-15T16:21:52Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![binarycat](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/binarycat/32/12210_2.png) [@binarycat](https://internals.rust-lang.org/u/binarycat)\
**Post date:** [March 15, 2025, 4:21pm UTC](https://internals.rust-lang.org/t/pre-rfc-fnstatic/22571/1 "2025-03-15T16:21:52Z")

</div>

# Problem statement

It is not possible to make function/closure combinators that return function pointers, even though it is possible to return a function pointer that wraps a trait associated function.

# Usecase

The main usecase is efficiently allowing erganomic wrappers for callbacks in C ffi.

For example, a wrapper around `libc::signal` that automatically wraps your signal handler so it saves and restores `errno` as required by the POSIX standard.

# The Trait

```rust
#![feature(unboxed_closures)]
#![feature(tuple_trait)]
use std::marker::Tuple;

trait FnStatic<Args>: Fn<Args> where Args: Tuple {
    fn call_static(args: Args) -> Self::Output;
}

```

This trait would be implemented for any implementor of `Fn` which is coercible to a function pointer.

Alternatively, instead of adding a new trait, equivalent functionality could be achieved by adding `Default` to this list of traits implemented by [function item types](https://doc.rust-lang.org/reference/types/function-item.html#r-type.fn-item.traits) (they are ZSTs, after all).

# Wrapping a trait-associated function

This is currently possible, but it would have much less boilerplate if `print_it` was a free function.

```rust
trait StaticPrinter {
    fn print_it();
}

struct One;

impl StaticPrinter for One {
    fn print_it() {
        print!("1");
    }
}

fn in_parens<P: StaticPrinter>() -> fn() {
    || {
        print!("(");
        P::print_it();
        print!(")");
    }
}

fn main() {
    in_parens::<One>()();
}

```

---

<div class="post-metadata">

**Author:** ![SabrinaJewson](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/sabrinajewson/32/9435_2.png) [@SabrinaJewson](https://internals.rust-lang.org/u/SabrinaJewson)\
**Post date:** [March 15, 2025, 4:47pm UTC](https://internals.rust-lang.org/t/pre-rfc-fnstatic/22571/2 "2025-03-15T16:47:14Z")

</div>

I would certainly be more in favour of the `Default` solution than `FnStatic`. With the `FnStatic` approach, it’s not clear how to actually call such a function in a stable manner (since `call`, and the fact it accepts tuples, is currently unstable), whereas `F::default()()` is obvious. I also think that `FnStatic` is a confusing name, because implementations are not required to be `'static`.

---

<div class="post-metadata">

**Author:** ![quaternic](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/quaternic/32/10440_2.png) [@quaternic](https://internals.rust-lang.org/u/quaternic)\
**Post date:** [March 15, 2025, 5:20pm UTC](https://internals.rust-lang.org/t/pre-rfc-fnstatic/22571/3 "2025-03-15T17:20:05Z")

</div>

The ideal syntax for calling a generic function item would be just `F()`. A separate `call_static` seems unnecessary, since the type `F` _is_ the function item that is called.

```rust
fn foo<F: FnStatic(i32)>() {
    F(42);
}

```

---

<div class="post-metadata">

**Author:** ![SabrinaJewson](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/sabrinajewson/32/9435_2.png) [@SabrinaJewson](https://internals.rust-lang.org/u/SabrinaJewson)\
**Post date:** [March 15, 2025, 5:56pm UTC](https://internals.rust-lang.org/t/pre-rfc-fnstatic/22571/4 "2025-03-15T17:56:33Z")

</div>

That would be very surprising, because `<F: FnStatic(i32)>` introduces `F` into the type namespace only, while `F(42);` requires `F` to be added to the value namespace. It’s not impossible for a type parameter to add to the value namespace, but it seems like a bit of a hack to have a rule like:

> If we can find `FnStatic` somewhere in the supertraits of a generic parameter `F`, add it to the value namespace.

So even though `F(42)` _looks_ very clean, I think `F::default()(42)` works better with how Rust is today.

---

<div class="post-metadata">

**Author:** ![quaternic](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/quaternic/32/10440_2.png) [@quaternic](https://internals.rust-lang.org/u/quaternic)\
**Post date:** [March 15, 2025, 7:18pm UTC](https://internals.rust-lang.org/t/pre-rfc-fnstatic/22571/5 "2025-03-15T19:18:51Z")

</div>

> [@SabrinaJewson](#):
>
> That would be very surprising, because `<F: FnStatic(i32)>` introduces `F` into the type namespace only, while `F(42);` requires `F` to be added to the value namespace.

Given that the trait bound does introduce associated functions of the trait to the value namespace, it's not unimaginable that in this very special case of function items (the kind of type that those associated functions themselves are), the trait would include the thing itself as a function. Kind of like `<F as FnStatic>::self`. But yes, probably that kind of thing should be syntactically distinct.

On a related note, we can't currently name function items as types, so how would the caller specify the generic parameter?

---

<div class="post-metadata">

**Author:** ![SabrinaJewson](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/sabrinajewson/32/9435_2.png) [@SabrinaJewson](https://internals.rust-lang.org/u/SabrinaJewson)\
**Post date:** [March 15, 2025, 7:21pm UTC](https://internals.rust-lang.org/t/pre-rfc-fnstatic/22571/6 "2025-03-15T19:21:55Z")

</div>

> [@quaternic](#):
>
> On a related note, we can't currently name function items as types, so how would the caller specify the generic parameter?

Well, they could presumably just accept an unused argument:

```rs
fn make_fn<F: Default + Fn()>(_: F) -> fn() {
    || F::default()()
}
make_fn(|| println!("hi"));

```

---

<div class="post-metadata">

**Author:** ![zackw](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/zackw/32/2071_2.png) [@zackw](https://internals.rust-lang.org/u/zackw)\
**Post date:** [March 15, 2025, 9:14pm UTC](https://internals.rust-lang.org/t/pre-rfc-fnstatic/22571/7 "2025-03-15T21:14:33Z")

</div>

Is the idea that the compiler emits a unique wrapper function for each function wrapped via this trait? I don't see any other way to make the wrapper be (convertible to) a true function pointer (rather than a `Fn*` trait object that cannot be passed to an FFI interface expecting a function pointer), but it is potentially a lot of code duplication. (This _is_ how your `StaticPrinter` example works today, though, so probably we can live with it.)

---

<div class="post-metadata">

**Author:** ![binarycat](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/binarycat/32/12210_2.png) [@binarycat](https://internals.rust-lang.org/u/binarycat)\
**Post date:** [March 16, 2025, 12:28am UTC](https://internals.rust-lang.org/t/pre-rfc-fnstatic/22571/8 "2025-03-16T00:28:13Z")

</div>

Yes, that is exactly the idea, to leverage the monomorphization pass.

This is actually how a lot of closures combinators already get compiled, and it's part of how iterator combinators like `map` manage to have actually decent performance.

---

<div class="post-metadata">

**Author:** ![SabrinaJewson](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/sabrinajewson/32/9435_2.png) [@SabrinaJewson](https://internals.rust-lang.org/u/SabrinaJewson)\
**Post date:** [March 16, 2025, 5:32pm UTC](https://internals.rust-lang.org/t/pre-rfc-fnstatic/22571/9 "2025-03-16T17:32:52Z")

</div>

For what it’s worth, I recently made [a macro-based polyfill for this feature on stable Rust](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=0d0804e7ee56e01acbe4ae5d590dacf5). However, there are several convenience limitations, and I’m not fully certain whether it’s sound. I would very much like to switch this code to a native feature.

---

<div class="post-metadata">

**Author:** ![programmerjake](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/programmerjake/32/5893_2.png) [@programmerjake](https://internals.rust-lang.org/u/programmerjake)\
**Post date:** [March 16, 2025, 7:39pm UTC](https://internals.rust-lang.org/t/pre-rfc-fnstatic/22571/10 "2025-03-16T19:39:13Z")

</div>

> [@SabrinaJewson](#):
>
> That would be very surprising, because `<F: FnStatic(i32)>` introduces `F` into the type namespace only, while `F(42);` requires `F` to be added to the value namespace.

one way to work around that is to use syntax that tells Rust to look in the type namespace:

```rust
pub fn foo<F: FnStatic(i32) -> u32>(v: i32) -> u32 {
    // like <T>::VALUE syntax for associated consts
    <F>(v) // or `<T as FnStatic(i32) -> u32>(v)` to disambiguate if it has multiple `FnStatic` impls
}

```

---

<div class="post-metadata">

**Author:** ![Mokuz](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mokuz/32/7225_2.png) [@Mokuz](https://internals.rust-lang.org/u/Mokuz)\
**Post date:** [March 17, 2025, 7:55am UTC](https://internals.rust-lang.org/t/pre-rfc-fnstatic/22571/11 "2025-03-17T07:55:54Z")

</div>

Making fn pointers `impl Default` might make some existing code unsound (assuming this is sound, not 100% sure). I don't know if such code exists but it's something to atleast think about.

```rust
mod seacret {
    // this function *should* be marked `unsafe` but because its private
    // it doesn't really _need_ to be
    fn private_function(ptr: *const u8) -> u8 {
        unsafe { *ptr }
    }
    
    // we make our getter `unsafe` so safe code cannot call `private_function`
 
    /// # Safety
    /// The returned function must not be exposed to untrusted code
    /// and it must not be called with a pointer that is not valid for
    /// reads
    pub unsafe fn get_private_function() -> fn(*const u8) -> u8 {
        private_function
    }
}

fn get_default<T: Default>(_f: unsafe fn() -> T) -> T {
    T::default()
}

fn main() {
    // currently this code fails to compile, but making `fn-pointer`s `impl Default`
    // changes that
    let f = get_default(seacret::get_private_function);
    
    let ub = f(0 as *const u8);
}

```

---

<div class="post-metadata">

**Author:** ![quaternic](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/quaternic/32/10440_2.png) [@quaternic](https://internals.rust-lang.org/u/quaternic)\
**Post date:** [March 17, 2025, 9:10am UTC](https://internals.rust-lang.org/t/pre-rfc-fnstatic/22571/12 "2025-03-17T09:10:21Z")

</div>

A [_function pointer_](https://doc.rust-lang.org/reference/types/function-pointer.html) type (e.g. `fn(*const u8) -> u8`) is not a ZST, and would never implement `Default`. The same idea almost works if the unsafe function returns the private [_function item_](https://doc.rust-lang.org/reference/types/function-item.html) as an abstract type:

```rust
/// # Safety: Must not call!
pub unsafe fn never_call_this() -> impl Fn() /* + Default */ {
    /// This private "safe" function must never be called
    fn cause_ub() {
        unsafe { std::hint::unreachable_unchecked() }
    }
    cause_ub
}

fn main() {
    let mut f = Default::default();
    if false {
        /// Safety: This is never executed
        unsafe {
            f = never_call_this();
        }
    }
    let ub = f();
}

```

But that also shows why this isn't quite enough: Even if the concrete type (the fn-item `fn() {cause_ub}`) did implement `Default`, the signature only promises to return some `impl Fn()` and the caller cannot assume it to also be `Default`. If the unsafe function did return `impl Fn() + Default`, its safety argument would break down.

---

<div class="post-metadata">

**Author:** ![programmerjake](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/programmerjake/32/5893_2.png) [@programmerjake](https://internals.rust-lang.org/u/programmerjake)\
**Post date:** [March 17, 2025, 9:13am UTC](https://internals.rust-lang.org/t/pre-rfc-fnstatic/22571/13 "2025-03-17T09:13:22Z")

</div>

> [@Mokuz](#):
>
> Making fn pointers `impl Default`

`fn` pointers can't impl `Default` since there is no default they could have. [`fn` item's types](https://doc.rust-lang.org/reference/types/function-item.html) (which are _not_ `fn` pointers, they are zero-sized types where every function has its own separate type where the type encodes which function it is) can implement `Default`, since they have only one possible value.

---

<div class="post-metadata">

**Author:** ![Mokuz](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mokuz/32/7225_2.png) [@Mokuz](https://internals.rust-lang.org/u/Mokuz)\
**Post date:** [March 17, 2025, 9:18am UTC](https://internals.rust-lang.org/t/pre-rfc-fnstatic/22571/14 "2025-03-17T09:18:52Z")

</div>

Somehow I missed that.

---

<div class="post-metadata">

**Author:** ![quaternic](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/quaternic/32/10440_2.png) [@quaternic](https://internals.rust-lang.org/u/quaternic)\
**Post date:** [March 17, 2025, 11:09am UTC](https://internals.rust-lang.org/t/pre-rfc-fnstatic/22571/15 "2025-03-17T11:09:04Z")

</div>

> [@SabrinaJewson](#):
>
> I would certainly be more in favour of the `Default` solution than `FnStatic`. With the `FnStatic` approach, it’s not clear how to actually call such a function in a stable manner (since `call`, and the fact it accepts tuples, is currently unstable), whereas `F::default()()` is obvious. I also think that `FnStatic` is a confusing name, because implementations are not required to be `'static`.

( Maybe `FnItem` could be a better name for the trait? )

While function items being `Default` might be the simplest solution to add, it feels lacking:

Firstly, I find `F::default()()` obfuscating, as it is visually quite close to just `F::default()`. The point of the expression is that `F` represents some function that we call, but it is literally first calling another function to get the thing to call. Any one of `F()`, `<F>()`, `F::call()`, `F::call_static()` or `F::call_item()` would be clearer.

More importantly, a generic bound of `F: Fn() + Default` doesn't rule out stateful closures. While they currently aren't, closures could potentially be `Default` in the future, and nightly features allow implementing `Fn()` for custom types anyway. With stateful closures as a possibility, there would be a subtle difference in behaviour between various reasonable ways to implement the same wrapper:

```rust
fn do_twice<F: Default + Fn()>(_: F) -> impl Default + Fn() {
    fn inner1<F: Default + Fn()>() {
        F::default()();
        F::default()();
    }
    fn inner2<F: Default + Fn()>() {
        let f = F::default();
        f();
        f();
    }
    fn inner3<F: Default + Fn()>() {
        let f = F::default();
        let g = F::default();
        f();
        g();
    }
    fn inner4<F: Default + Fn()>() {
        let f = F::default();
        F::default()();
        f();
    }
    inner1::<F>
}

```

Because really, a trait bound of `F: Default + Fn()` is asking for a type with _two_ operations: `fn() -> F {<F as Default>::default}` and `fn(&F) {<F as Fn()>::call}`, when we mostly just needed the single operation `fn() {<F as FnStatic()>::call_static}` which doesn't even need to manifest a value of `F`.

---

<div class="post-metadata">

**Author:** ![SabrinaJewson](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/sabrinajewson/32/9435_2.png) [@SabrinaJewson](https://internals.rust-lang.org/u/SabrinaJewson)\
**Post date:** [March 17, 2025, 3:29pm UTC](https://internals.rust-lang.org/t/pre-rfc-fnstatic/22571/16 "2025-03-17T15:29:54Z")

</div>

> [@quaternic](#):
>
> More importantly, a generic bound of `F: Fn() + Default` doesn't rule out stateful closures.

Well, one could always use `FnOnce() + Default`. I suppose a practical disadvantage is that one does not implicitly get extra bounds like `Send + Sync + Clone + Copy` with just `Default` alone, but I don’t know how relevant this is. Maybe a `FnItem` trait could have `Send + Sync + Clone + Copy + Default + Fn` as supertraits.

Another consideration of the `FnItem` design is that we’d have to have `AsyncFnItem` as well – not terrible but certainly an increase in standard library API surface.

The one thing that does bother me about `<F>()` is that it’s a whole new syntax for a relatively niche feature. I would guess that most intermediates would not know it, and coming across it in a codebase is hard to use a search engine for. On the other hand, even though `F::default()()` _looks_ weird, it’s perfectly predictable.

The other options don’t seem great – `F::call` conflicts with `Fn::call`, and `F::call_static` uses the already too-overloaded term “static” ­ – but `F::call_item` is searchable. It does seem weird that only `call_item` and not `call_mut` or `call_once` are exposed, and that it’ll be the only method call in the language to support variadics, but functions already have special syntax and this is at least predictable.

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [March 17, 2025, 8:26pm UTC](https://internals.rust-lang.org/t/pre-rfc-fnstatic/22571/17 "2025-03-17T20:26:20Z")

</div>

Another alternative could be to use a `const` function pointer as a generic parameter, e.g.

```rust
fn in_parens<const F: fn()>() -> fn() {
    || {
        print!("(");
        F();
        print!(")");
    }
}

fn main() {
    in_parens::<{ || print!("1") }>()();
}

```

It's perhaps not the most elegant syntax at the call site, and it'll require a way to encode function items into valtrees (for the generic monomorphization), but it resolves the "doesn't define a name in the value namespace" issue fairly directly.

> [added later] Actually, no, yeah, const equality for function pointers is problematic. The codegen issue is resolvable (handle it like monomorphization over the function item) but equality of function pointers is not const friendly.

But I also think the syntax issue isn't that big of a deal, nor is the awkward `F::default()()` calling syntax, as I expect the most common way to use it would actually still provide a (zero sized) value, e.g.:

```rust
trait FnItem<…> = Fn<…> + Default + Copy + /* autotraits */ + CoerceInto<fn<…>>;

fn in_parens<F: FnItem()>(f: F) -> impl FnItem() {
    move || {
        print!("(");
        f();
        print!(")");
    }
}

```

"All" this needs is a rule that function items implement `Default` and a rule that closures that only capture (zero or more) 1-ZST types that implement `Default` also implement `Default` and can be coerced into function pointers.

Function items currently are nameable only in the value namespace and not the type namespace, anyway.

---

<div class="post-metadata">

**Author:** ![binarycat](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/binarycat/32/12210_2.png) [@binarycat](https://internals.rust-lang.org/u/binarycat)\
**Post date:** [May 7, 2025, 3:31am UTC](https://internals.rust-lang.org/t/pre-rfc-fnstatic/22571/18 "2025-05-07T03:31:16Z")

</div>

I hadn't considered simply adjusting the rules for which closures can be coerced to function pointers.

another alternative to consider is to make `FnItem` an unimplemenable trait with no methods, and make it have `Default` as a supertrait. This would avoid any potential future weirdness caused by implementing Default on coroutines or closures.

---

<div class="post-metadata">

**Author:** ![binarycat](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/binarycat/32/12210_2.png) [@binarycat](https://internals.rust-lang.org/u/binarycat)\
**Post date:** [May 15, 2025, 2:50pm UTC](https://internals.rust-lang.org/t/pre-rfc-fnstatic/22571/19 "2025-05-15T14:50:58Z")

</div>

you can maybe transmute from unit to do this?

---

<div class="post-metadata">

**Author:** ![RalfJung](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ralfjung/32/2415_2.png) [@RalfJung](https://internals.rust-lang.org/u/RalfJung)\
**Post date:** [May 23, 2025, 3:13pm UTC](https://internals.rust-lang.org/t/pre-rfc-fnstatic/22571/20 "2025-05-23T15:13:42Z")

</div>

> [@CAD97](#):
>
> Another alternative could be to use a `const` function pointer as a generic parameter, e.g.

I doubt that's ever going to be allowed. Const generic parameters need a sensible notion of equality, which function pointers very much do not have.

[Next page](https://internals.rust-lang.org/t/pre-rfc-fnstatic/22571.md?page=2)
