Stream: general

Topic: Homogenous conversion of Error types and trait objects


Jake Goulding (May 10 2019 at 14:12, on Zulip):

previously...

I have a procedural macro that wants to implement Error for an enum containing different types of underlying source errors (SNAFU). I keep running into a problem with the differences of trait objects and concrete objects when converting them to a reference trait object:

enum Error {
    TraitObjectSendSync(Box<dyn error::Error + Send + Sync + 'static>),
    TraitObjectSend(Box<dyn error::Error + Send + 'static>),
    TraitObjectSync(Box<dyn error::Error + Sync + 'static>),
    TraitObject(Box<dyn error::Error + 'static>),
    Boxed(Box<io::Error>),
    Unboxed(io::Error),
}
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        use Error::*;

        // Works, but the match arms are heterogeneous and cannot be
        // automatically determined / generated via a procedural macro
        Some(match *self {
            TraitObjectSendSync(ref e) => &**e,
            TraitObjectSend(ref e) => &**e,
            TraitObjectSync(ref e) => &**e,
            TraitObject(ref e) => &**e,
            Boxed(ref e) => e,
            Unboxed(ref e) => e,
        })
    }

The playground has various attempts I've made:

None work. Is there any way I can have this work without requiring users to annotate if something is a trait object?

simulacrum (May 10 2019 at 14:18, on Zulip):

In 2018 I guess maybe looking for dyn Foo in the type?

simulacrum (May 10 2019 at 14:18, on Zulip):

as a heuristic, anyway

Jake Goulding (May 10 2019 at 14:24, on Zulip):

I'd be pretty sad about a heuristic :-(

RalfJ (May 10 2019 at 14:26, on Zulip):

I wonder why &*e does not work

error[E0277]: the size for values of type `(dyn std::error::Error + 'static)` cannot be known at compilation time

why does it even get that as an rvalue?

RalfJ (May 10 2019 at 14:27, on Zulip):

oh, probably because it uses some impl<T> Error for Box<T> where T: Error

Jake Goulding (May 10 2019 at 14:27, on Zulip):

I believe that's in the right area, @RalfJ

RalfJ (May 10 2019 at 14:27, on Zulip):

is that impl a thing? can we make it T: ?Sized?

Jake Goulding (May 10 2019 at 14:28, on Zulip):

(You had that idea already ;-))

RalfJ (May 10 2019 at 14:28, on Zulip):

lol

RalfJ (May 10 2019 at 14:28, on Zulip):

at least I am consistent :P

RalfJ (May 10 2019 at 14:29, on Zulip):

that wouldnt give you the trait object you want (no need to carry that extra Box around), but I guess if its only for errors anyway the extra ptr indirection is not so bad

Jake Goulding (May 10 2019 at 14:40, on Zulip):

I feel like I want "deref a value until you get to a trait and then take a reference". That kind of structure always leads to either auto-traits or specialization, which isn't a good road for stable stuff.

Jake Goulding (May 10 2019 at 17:43, on Zulip):

The wonderful @kennytm solved it for me with a custom trait and relying on method auto-deref.

RalfJ (May 10 2019 at 17:52, on Zulip):

nice!

RalfJ (May 10 2019 at 17:52, on Zulip):

still might want to add that T: ?Sized to whatever impl doesnt have it, though^^

RalfJ (May 12 2019 at 14:54, on Zulip):

reported as https://github.com/rust-lang/rust/issues/60759 (I couldnt find an existing report)

Jake Goulding (May 13 2019 at 02:07, on Zulip):

Thank you! I just tried to add the implementation, saw there were errors, and said "oh, I guess it can't exist"

Last update: Nov 20 2019 at 12:25UTC