Downcast when use Enum as a way for static dispatch

Continuing the discussion from When to use dynamic dispatch?:

I know I can have static dispatch with Enum like this:

struct Dog;
struct Cat;

pub enum Animal {
    Dog(Dog),
    Cat(Cat)
}

trait Run {
    fn run(&self);
}

impl Run for Animal {
    fn run(&self) {
        match self {
            Animal::Dog(dog) => {
                // dog run
            },
            Animal::Cat(cat) => {
                // cat run
            }
        }
    }
}

fn animal_run(animal: &Animal) {
    animal.run();
}

// static dispatch
animal_run(Animal::Dog(Dog));
animal_run(Animal::Cat(Cat));

And when I want to downcast Animal to Dog or Cat, I can write a method like below:

impl Animal {
    pub fn as_dog(&self) -> Result<&Dog, Error> {
        if let Animal::Dog(dog) = self {
            dog
        } else {
            Err(format_err!("downcast Animal to Dog failed"))
        }
    }
}

My question is, when downcast a Enum, should I return a Result or just panic? I personally tend to panic directly, though.

impl Animal {
    pub fn as_dog(&self) -> &Dog {
        if let Animal::Dog(dog) = self {
            dog
        } else {
            panic!("failed to convert ui_state to editable dog")
        }
    }
}

I'm not sure whether it's really a problem, but I want to know if there's any best practice to downcast?

This is not specific to the downcasting, this is a question of error handling in general.

When you are creating a library, by any means don't panic, if the caller can recover from the error (in this case, by providing the correct value). Panics in libraries must be reserved to the case of internal bugs, like "reaching the should-be-unreachable code".

When the code is in binary - AFAIK there's no best practices. I'd say that the handling should be the same as above, however: if the error is recoverable - return it (and maybe expect on it later with a meaningful message), if it's not - panic here, to get a possibly useful backtrace.

1 Like

Looking at the standard library (Option, Result) I think the idiomatic method names would be unwrap_dog/cat (Option::unwrap(_none)) for the panicking version and dog/cat (Result::ok/err) for the version that returns Option<Dog/Cat>.

4 Likes