Error handling inside RefCell's map closure

Hi,

Does anyone have a workable solution for bubbling Result<T,E> errors out of map closures that need to return a reference? For example, the map closure of RefCell

struct MyStruct {
    contents: RefCell<Box<dyn SomeTrait>>
}

impl MyStruct {
    pub fn access<T>(&self) -> Result<Ref<T>, String>
    where T: Any + 'static,
    {
        let my_ref = self.contents.borrow();

        let mapped_ref = Ref::map(my_ref, |my_ref| {
            my_ref.expensive_function_that_may_fail::<T>()?
        
            //Obviously the ? doesn't work inside the closure.
            // But I don't want to unwrap() the result because the function often fails
            // And the cost of the function means that preflighting it isn't an option.
        });
    
        Ok(mapped_ref)
    }
}

I see std::Cell::Ref::filter_map but it's unstable, and only takes an option (as opposed to a Result)

What's the best idiomatic solution that people use in this case?

Thank you.

Let me ask the question slightly differently: Is there any reason this is a bad idea?

struct MyStruct {
    contents: RefCell<Box<dyn SomeTrait>>
}

impl MyStruct {
    pub fn access<T>(&self) -> Result<Ref<T>, String>
    where T: Any + 'static,
    {
        let my_ref = self.contents.borrow();

        let function_out = my_ref.expensive_function_that_may_fail::<T>()?

        //Safety Note: transmuted can't outlive of my_ref because we map my_ref into it
        let transmuted = unsafe { &*((&*function_out) as *const dyn Any as *const T) };

        Ok(Ref::map(my_ref, |_| {
            transmuted
        }));
    }
}

Thank you.

You can do this without any unsafe by passing the error out of the closure in a mutable Option variable, then returning an arbitrary &'static reference to satisfy Ref::map. Then if the variable contains an error, you ignore the reference and return Err.

It's a workaround for not having Ref::filter_map, and it's inelegant, but it works.

1 Like

Oh. Nice. I'd forgotten the closure was FnOnce.

Thanks!

Yes. You are using unsafe to circumvent the borrow checker. This is recognizably an anti-pattern, and it usually leads to unsoundness and Undefined Behavior.

You shouldn't use unsafe for "fixing" compiler errors, and it definitely shouldn't be the first tool you reach for. You should try really hard to solve problems using safe language and library features instead.

The exceptions are when you want to perform FFI calls to C, or when you find a case where micro-optimizing a data structure requires you to manually manage memory. The latter, however, is exceedingly rare, so as a first-order approximation, the advice is "don't use unsafe unless you need FFI".

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.