What's the suitable design pattern for error handling in in-place data updating operation?


#1

The error handling in rust is mainly based on Result<T, Err>, which is suitable for functions that have return values, especially pure-functional style functions.

What if I need to handle the error condition for in-place updating data member condition?

Say I have some structure with some data member, and I impl some fu for it, which calculate the new value, and write back to self. Such function does not necessarily have return value. What is the proper design pattern for error handling of such kinds of functions?

I understand that at least we can return error code, but it is ugly, isn’t it? Or maybe rust encourages we write codes in a functional-style? but this some times causes low performance.

In languages with exception, we can always throw an exception, what about for rust?


#2

You have two options. One is:

    fn mutate(&mut self, ...) -> Result<(), Error>

So, you do mutation and return ugly Result<(), Error>. It tempts to not consume the result, but compiler will warn you. But many people (including me) do not like it.

Other option is to have:

   fn mutate(self, ...) -> Result<Self, Error> { ... }

which instead of mutating the structure consumes the original and outputs new result (which might be just original one with couple of variables mutated). And this should be fast and efficient.


#3

As a counter-argument, Result<(),_> works fine with the ? operator, and lack of the value doesn’t get in the way:

obj.mutate()?;

but if you don’t want to destroy the object, Result<Self,_> requires re-taking the object:

let obj = obj.mutate()?;

which is more verbose, especially with conditionals:

if cond {
   obj.mutate()?; 
}

vs

let obj = if cond {
   obj.mutate()?
} else { 
   obj 
};