From<Fn() -> T> for T

Why isn't this implemented by default?

impl<T, F: Fn() -> T> From<F> for T {
    fn from(f: F) -> Self {
        f()
    }
}

This could allow us to write

fn take_number(value: impl Into<f64>) {
  println!("Taken number: {}", value.into())
}

fn complex_math() -> f64 {
  1.0 + 2.0
}

take_number(10.0)
take_number(complex_math)

It conflicts with the blanket impl<T> From<T> for T if nothing else.

3 Likes

That's it. I just wrote a custom MyFrom/MyInto trait to test it.
Now I am wondering what could be improved in the type system to deal with such constraints.

It's possible for a type F to implement Fn() -> F, for which both impls in the initial post apply, so they actually overlap. What should happen in that case?

1 Like

The overlap isn't a false positive, FWIW. fn fake_val<T> -> T { unimplemented!() } can theoretically be the recursive type F = fn() -> F.

Actually creating that monomorphization might not be possible, but the type is legal. And the general case for implementable traits is trivial to construct; just do impl Trait for T { type Output = Self; }.

2 Likes

Isn't this cleaner?

take_number(complex_math());
2 Likes

You can create a self-returning function and don't need generics, but have to hide the recursion from the type system a bit :slight_smile:.

Might work with coinduction?

1 Like

I usually think of x.into() as not losing any information about x, but Fn() -> T isn't just a lazy T because you can do things with interior mutability.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.