Rustacean way to deal with function that can take different args

Hello,

I'm wondering what the idiomatic way to deal with this situation is. I'm implementing some time-value-of-money (TVM) formulas, and sometimes the same thing is calculated with different inputs. For example:

image

Should I just write two different pmt functions pmt_pv and pmt_fv or is there a more idiomatic way to handle this (in the absence of multiple dispatch)?

I guess another option would be to have a single pmt function that accepts an enum that is either pv or fv and then pmt calls pmt_pv or pmt_fv based on the enum...?

I would just write separate functions. If one is significantly more common, maybe it could claim the unsuffixed name, but generally it's best to be explicit.

9 Likes

Another possibility: If PV_A and FV_A are different types you control, you could implement methods pmt(self,i, N) on them. Maybe define a trait like

trait Pmt {
    type P;
    fn pmt(self, i: i32, N: u32) -> P;
}

if you need to/want to abstract over those types.

4 Likes

A variant of @KillTheMule s suggestion is to have a function that takes the common parameters, and returns a struct that has methods for the giving the alternative versions and calculating the actual results. Something like this:

struct Pmt {
    v_a: f64;
}
impl Pmt {
    fn pmt(v_a: f64) -> Self {
        Pmt { v_a }
    }
    fn p(self, p: f64) -> f64 {
        self.v_a * p / more_stuff
    }
    fn f(self, f: f64) -> f64 {
        self.v_a * f / other_stuff
    }
}

/// usage:
let result = Pmt::pmt(some_v_a).p(some_p);

When used for initialising complex data structures, this is called the "builder pattern", and is quite common in rust crates. But it is often usefull for calculations as well. There can also be more types involved for intermediate steps when there is more flexibility in given arguments.

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.