Can't downcast Box<Any>

Hi,

I'm trying to write a small framework and need a Box I can downcast for a cache. I ran into this problem and frewsxcv helped me with a small piece of code we both expected to work but it doesn't:

use std::any::Any;
use std::fmt::Display;

fn main() {
    log(Box::new("hi"))
}

fn log<T: Any + 'static>(value: Box<T>) {
    let x = value.downcast();
}

rust playground

It gives the error:

<anon>:9:19: 9:27 error: no method named `downcast` found for type `Box<T>` in the current scope
<anon>:9     let x = value.downcast();

Shouldn't this work? If not is the documentation outdated? It says there should be a .downcast method for Box types.

Any feedback much appreciated!

Cheers,
Tinco

That's because downcast is implemented on Box<Any + 'static>, not Box<T> where T: Any + 'static. The first is a boxed trait object (a concrete type), the second is actually a class of types (all Box<T> where T has a 'static lifetime and implements Any). At compile time, log will be monomorphized and the type of value will be Box<&str>.

You can fix this by casting the Box<&str> to a Box<Any> (unsizing &str to Any):

use std::any::Any;
use std::fmt::Display;

fn main() {
    log(Box::new("hi"))
}

fn log<T: Any + 'static>(value: Box<T>) {
    let x: Result<Box<&str>, _> = (value as Box<Any + 'static>).downcast();
}

However, I doubt this is what you want to do. There's no reason to downcast in this case because you already know the type (it's T).

You probably intended to write:

use std::any::Any;
use std::fmt::Display;

fn main() {
    log(Box::new("hi"))
}

fn log(value: Box<Any + 'static>) {
    let x: Result<Box<&str>, _> = value.downcast();
}

If you find my explanation a bit dense/opaque, please say so. There's a lot of jargon here.

1 Like

Ah thanks a lot! That makes total sense. Please allow me a follow up question, which is closer to my actual use case which also raises the no method downcast error:

use std::any::Any;
use std::fmt::Display;

fn main() {
    log(Box::new("hi"))
}

fn log(value: Box<Any + Sync + 'static>) {
    let x: Result<Box<&str>, _> = value.downcast();
    println!{"{}", *x.unwrap()};
}

When I add the Sync trait it doesn't work anymore. I'm a bit confused by that, the adding of traits shouldn't matter for this case should it?

Same error as before, downcast is only implemented for particular variants of Box<Any>: Box in std::boxed - Rust

It works if you then manually cast to the appropriate type:

let x: Result<Box<&str>, _> = (value as Box<Any+'static>).downcast();

You can also write it with UFCS:

let x: Result<Box<&str>, _> = <Box<Any+'static>>::downcast(value);

I'm not sure why this version isn't automatic:

let x: Option<&&str> = (&*value).downcast_ref();

Alright, I guess that makes sense. I get a new exception now but I'll make a new topic for it as it seems to be unrelated. Thanks!