Maths with Results

What's the best way to add/subtract/divide/multiply Results without many '?' marks (E.g. Result )? Is there a crate that implements a numeric type with arithmetic that propagates errors?

(maybe one that takes a num-trait as a type parameter ?)

I couldn't find something out there, but I'm sure someone must have already tried doing something like this?

I had a similar problem while implementing arithmetic ops for JSON data. I had to define it as

#[derive(Clone, Debug)]
pub enum Json {
    Null,
    Bool(bool),
    Integer(Integral),
    Float(Floating),
    String(String),
    Array(Vec<Json>),
    Object(Vec<Property>),
    // Hidden variants
    #[doc(hidden)]
    __Error(Error),
}

If any operation in a JSON arithmetic expression fails, it will create an __Error variant and all parent operation will short circuit when one of its operand is __Error variant.

1 Like

You could try using the newtype pattern to define a wrapper over result and then implement standard arithmetic traits.
For example:

use std::ops::Add;

#[derive(Debug)]
struct MyResult(Result<f64, String>);

impl Add for MyResult {
    type Output = Self;
    fn add(self, other: Self) -> Self::Output {
        match (self, other) {
            (MyResult(Ok(a)), MyResult(Ok(b))) => MyResult(Ok(a + b)),
            _ => MyResult(Err(String::from("Can be handled better to propagate instead.")))
        }
    }
}

fn main() {
    let a = MyResult(Ok(5.0));
    let b = MyResult(Ok(2.0));
    let c = a + b;
    println!("{:?}", c);
}
1 Like

If only one side is a Result, then Result.map(|x| x + 2) can do it. Otherwise, ? is probably the way to go.

@BlueBlazin yeah that was kind of what I was thinking.
Just figured there must be a crate out there doing this already. There's likely to be a lot of maths so less friction the better.

If it can just look like maths that would be best. The ? marks also incur brackets. E.g. ((a + b)? + (c + d)?)?

Maybe I just retrofit the '?' with a math! macro...

@gilescope If you care about performance, you probably have to use f32 or f64. They have NaNs which signal that a value is not valid. Unless you need specific error reasons, I would suggest to use NaN to your advantage.