#implementation of resolve is not generic enough

18 messages · Page 1 of 1 (latest)

naive goblet
#
 Resolve<'a> {
    fn resolve(ctx: &'a String) -> Self;
}

struct Foo<'a> {
    inner: &'a String
}

impl<'a> Resolve<'a> for Foo<'a> {
    fn resolve(ctx: &'a String) -> Self {
        Foo {
            inner: &ctx
        }
    }
}

struct Bar;

impl<'a> Resolve<'a> for Bar {
    fn resolve(_ctx: &'a String) -> Self {
        todo!()
    }
}

trait System<'a, A> {
    fn run(&self, ctx: &'a String); 
}

impl<'a, A, T> System<'a, A> for T where T: Fn(A), A: Resolve<'a> {
    fn run(&self, ctx: &'a String) {
        let x = A::resolve(ctx);

        (self)(x)
    }
}

fn foo(_foo: Foo) {}
fn bar(_bar: Bar) {}

fn box_fn<A>(x: impl for<'a> System<'a, A> + 'static) -> Box<dyn Fn(&String)> { 
    Box::new(move |ctx| x.run(ctx))
}

fn main() {
    // implementation of System is not general enough
    box_fn(foo);
    box_fn(bar);
}
#

Im currently trying to add lifetimes to my framework and I've come across this. I want to provide a mechanism to make parameters that are resolvable without owning their values to avoid cloning large amounts of data. This is the minimum example of what I am doing

drowsy arch
#

Your code got cut off (particularly for what might be the important part)

#

Also, you didn't provide the actual error output

naive goblet
#
error: implementation of `System` is not general enough
  --> src/main.rs:46:5
   |
46 |     box_fn(foo);
   |     ^^^^^^^^^^^ implementation of `System` is not general enough
   |
   = note: `for<'a> fn(Foo<'a>) {foo}` must implement `System<'0, Foo<'_>>`, for any lifetime `'0`...
   = note: ...but it actually implements `System<'1, Foo<'_>>`, for some specific lifetime `'1````
drowsy arch
#

If it's not cut off, this syntax is wrong.

naive goblet
drowsy arch
#

A the function-parameter for the System implementation and 'a the unbounded lifetime are disjoint, and A is just as the error says, a particular lifetime

#

Think about box_fn<A>(...), that A can't satisfy for<'a> System<'a, A> unless A: 'static

naive goblet
#

I am aware of why this fsils

#

Fails

#

I dont have a good solution to represent this

#

I understand this does not represent a universal singular implementation but that is what I would like

grave kraken
#

You could do something like this I think....essentially make the Resolve trait allow a different type as output than Self.....this way it doesn't matter what lifetime it uses initially for Foo (deduced from the function passed in), it can still resolve it to the correct lifetime when resolved with a specific string of that lifetime. It does leave it upto the implementor though to make sure they produce the correct type as output

#

?play

trait Resolve<'a> {
    type Output;
    fn resolve(ctx: &'a String) -> Self::Output;
}

#[derive(Debug)]
struct Foo<'a> {
    _inner: &'a String
}

impl<'a, 'b> Resolve<'b> for Foo<'a> {
    type Output = Foo<'b>;
    fn resolve(ctx: &'b String) -> Self::Output {
        Foo {
            _inner: &ctx
        }
    }
}

#[derive(Debug)]
struct Bar;

impl<'a> Resolve<'a> for Bar {
    type Output = Self;
    fn resolve(_ctx: &'a String) -> Self::Output {
        Self
    }
}

trait System<'a, A> {
    fn run(&self, ctx: &'a String);
}

impl<'a, A, T> System<'a, A> for T where T: Fn(A) + Fn(A::Output), A: Resolve<'a> {
    fn run(&self, ctx: &'a String) {
        let x = A::resolve(ctx);
        (self)(x)
    }
}

fn foo(foo: Foo) {
    println!("Calling foo with {foo:?}");
}

fn bar(bar: Bar) {
    println!("Calling bar with {bar:?}");
}

fn box_fn<A>(x: impl for<'a> System<'a, A> + 'static) -> Box<dyn Fn(&String)> { 
    Box::new(move |ctx| x.run(ctx))
}

fn main() {
    let foo_boxed = box_fn(foo);
    let bar_boxed = box_fn(bar);
    let string = String::from("Hello, World!");
    foo_boxed(&string);
    bar_boxed(&string);
}
normal nightBOT
#
Calling foo with Foo { _inner: "Hello, World!" }
Calling bar with Bar```