num-traits icon indicating copy to clipboard operation
num-traits copied to clipboard

Why does AsPrimitive require 'static?

Open xplorld opened this issue 6 years ago • 3 comments

I don't see any reason. I want to cast runtime primitives in generic functions and encountered lifetime issues. If we remove the 'static I guess it still works.

xplorld avatar Jun 12 '19 01:06 xplorld

The idea is that this trait is only meant to be used for true primitives, with cheap as conversions, and perhaps for wrappers thereof. The Copy + 'static requirement doesn't fully guarantee this, but it's a decent marker.

It would be a breaking change to remove those requirements, because other code can implicitly make use of those as supertraits of AsPrimitive.

Can you give an example of how this causes lifetime issues for you?

cuviper avatar Jun 13 '19 01:06 cuviper

I am writing a wrapper which takes a u32, as-cast it into i32, doing transformation (i32 -> i32) and as-cast it back to u32. It is like:

fn wrapper(F f) -> G where F: Fn(i32) -> i32, G: Fn(u32) -> u32.

The problem is, I have to write many of them, including u8, u32, u64. I want to write something like

fn wrapper<T, U, F>(F f) -> G where
  T: Copy + AsPrimitive<U>,
  U: Copy + AsPrimitive<T>,
  F: Fn(T) -> T,
  G: Fn(U) -> U

and of course it could not work because of the 'static constraint.

Could you shed some light on that?

xplorld avatar Jun 17 '19 02:06 xplorld

Please include the actual code and the error messages when you report a problem. The snippets you've given are not even valid Rust syntax, regardless of any type or lifetime issues.

I suspect your problem is the lifetime for f, which you'll need to move into the returned closure. Plus that return needs to be an anonymous type, which is perfect for impl Trait.

This works:

pub fn wrapper<T, U, F>(f: F) -> impl Fn(U) -> U
where
    T: AsPrimitive<U>,
    U: AsPrimitive<T>,
    F: Fn(T) -> T,
{
    move |x| f(x.as_()).as_()
}

For more flexibility for the caller, consider taking and returning FnMut instead, so it's possible to have mutable state associated with the F closure.

pub fn wrapper<T, U, F>(mut f: F) -> impl FnMut(U) -> U
where
    T: AsPrimitive<U>,
    U: AsPrimitive<T>,
    F: FnMut(T) -> T,
{
    move |x| f(x.as_()).as_()
}

cuviper avatar Jun 25 '19 20:06 cuviper