How would you avoid code duplication here?

For example:

impl Ledger {
    pub fn new() -> Self {
        Ledger {
            expenses: Vec::new(),
            balance: 0.0
        }
    }

    pub fn withdraw(amount: f64) {
        let expense = Expense::new(amount, ExpenseFlow::Out);
        self.expenses.push(expense);
        self.balance -= amount;
    }

    pub fn deposit(amount: f64) {
        let expense = Expense::new(amount, ExpenseFlow::In);
        self.expenses.push(expense);
        self.balance += amount;
    }
}

The only difference between the two methods is that one substracts and the other adds a value to the balance property.

I guess I could do something like this:

// In ledger impl
fn add_expense(amount: f64, flow: ExpenseFlow) {
    let expense = Expense::new(amount, flow);
    self.expenses.push(expense);
    self.balance = match flow {
        ExpenseFlow::In => self.balance + amount,
        ExpenseFlow::Out => self.balance - amount
    };
}

...but having to bring ExpenseFlow into scope at every module you call this method just doesn't sit right with me. Is it reasonable to do it this way, or would you suggest another approach?

There is not that much duplication as is, but you can extract the two lines of shared code like this:

    pub fn withdraw(&mut self, amount: f64) {
        self.log_expense(amount, ExpenseFlow::Out);
        self.balance -= amount;
    }

    pub fn deposit(&mut self, amount: f64) {
        self.log_expense(amount, ExpenseFlow::In);
        self.balance += amount;
    }

    fn log_expense(&mut self, amount: f64, flow: ExpenseFlow) {
        let expense = Expense::new(amount, flow);
        self.expenses.push(expense);
    }

4 Likes

Yes that makes sense, thanks a lot!