Returning mutable refs from traits

I tried to make a minimal reproducible source

use std::{borrow::BorrowMut, collections::HashMap};

struct Database(HashMap<String, i32>);

type IntMut<'a> = &'a mut i32;

impl Database {

	fn insert(&mut self, key: &str, val: i32) {
		self.0.insert(key.to_owned(), val);
	}

	fn get(&mut self, key: &str) -> IntMut {
		self.0.get_mut(key).expect("Value not found").borrow_mut()
	}

}

pub struct DatabaseManager(Database);

pub trait Manager<T> {
	fn manage(&mut self) -> T;
}

impl <'a> Manager<IntMut<'a>> for DatabaseManager {
	fn manage(&mut self) -> IntMut<'a> {
		self.0.get("d").borrow_mut()
                // ^ ERROR cannot infer appropriate lifetime for autoref due to conflicting requirements ...
	}
}

fn main() {

	let mut db = Database(HashMap::new());

	db.insert("d", 3);

	let mut dbm = DatabaseManager(db);

	for _ in 0..10 {
		let d = dbm.manage();
		*d += 1;
		println!("{}", d);
	}

}

In short: need to return mutable refs in a similar scenario, how would I go about doing this?

This signature:

pub trait Manager<T> {
	fn manage(&mut self) -> T;
}

Means, "however long or short you borrow self for, I can return you a T". But this implementation:

impl <'a> Manager<IntMut<'a>> for DatabaseManager {
	fn manage(&mut self) -> IntMut<'a> {
		self.0.get("d").borrow_mut()
                // ^ ERROR cannot infer appropriate lifetime for autoref due to conflicting requirements ...
	}
}

Attempts to return a T = IntMut<'a> that is a borrow of &mut self, for any 'a, even when that borrow was arbitrarily short. Imagine making this call, for example:

let foo: IntMut<'static> =
  <DatabaseManager as Manager<IntMut<'static>>::manage(&mut dm);

When you implemented Manager<IntMut<'a>> for DatabaseManager for any 'a whatsoever, you promised this was possible. But given your implementation, it is not.


To make this work, you need some way to tie the lifetime of the borrow in fn manage(&mut self) to the return type. Here I've added a lifetime parameter to the trait:

pub trait Manager<'borrow, T> {
	fn manage(&'borrow mut self) -> T;
}

impl <'a> Manager<'a, IntMut<'a>> for DatabaseManager {
	fn manage(&'a mut self) -> IntMut<'a> {
		self.0.get("d").borrow_mut()
	}
}
2 Likes

The code here will compile.
The TL;DR is that change the trait to be:

pub trait Manager<'a, T> {
	fn manage(&'a mut self) -> T;
}

But I am not sure how idiomatic it is.
Edit: Since @quinedot certifies it, I would take it to be okay.

1 Like

Okay, that worked, but I'm afraid that wasn't actually the whole issue, I'll try to explain what I'm actually trying to do: I'm writing an interpreter for a small pseudolang, I have a Value enum which holds the representation of the data types of the pseudolang. I want to be able to pass around mutable references to the data that I already have, so that I can mutate it. But some methods on the interpreter creates new values (as when evaluating an operation or a literal), and I can't pass mutable references to it. How can I go about doing this?

I tried to make this small snippet to represent the error That I'm getting:

pub trait Manager<'a, T> {
    fn get(&'a mut self, flag: bool) -> T;
	fn get_id(&'a mut self) -> T;
	fn new_9(&'a mut self) -> T;
}

impl <'a> Manager<'a, IntMut<'a>> for DatabaseManager {
    fn get(&'a mut self, flag: bool) -> IntMut<'a> {
        if flag { self.get_id() }
        else { self.new_9() }
    }

	fn get_id(&'a mut self) -> IntMut<'a> {
		self.0.get("id").borrow_mut()
	}

	fn new_9(&'a mut self) -> IntMut<'a> {
		let mut v: i32 = 9;
		v.borrow_mut()
       // ^ cannot return value referencing local variable
	}
}

I think I could return an enum that has two variants, one for owned data and one for mutable references, but I feel that would add a lot of overhead.
I can't have two different types because there's is a method that "routes" to the other methods.

EDIT: I tried it, and this solution worked, but I'd like to know if there is a better solution:

enum Int<'a> {
	Val(i32),
	Mut(&'a mut i32),
}

impl <'a> AddAssign<i32> for Int<'a> {
	fn add_assign(&mut self, rhs: i32) {
		match self {
			Self::Val(n) => *self = Self::Val(*n + rhs),
			Self::Mut(n) => **n = n.clone() + rhs,
		}
	}
}

impl <'a> Display for Int<'a> {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		match self {
			Self::Val(n) => write!(f, "{}", n),
			Self::Mut(n) => write!(f, "{}", n),
		}
	}
}

impl <'a> Manager<'a, Int<'a>> for DatabaseManager {
	fn get(&'a mut self, flag: bool) -> Int<'a> {
			if flag { self.get_id() }
			else { self.new_9() }
	}

	fn get_id(&'a mut self) -> Int<'a> {
		Int::Mut(self.0.get("id").borrow_mut())
	}

	fn new_9(&'a mut self) -> Int<'a> {
		let v: i32 = 9;
		Int::Val(v)
	}
}

It looks like you are trying to return either a owned value or a borrowed reference. So you may replace Int in your code with MaybeOwned or Cow depending upon if the underlying type implements Clone.

1 Like

You are the master of lifetime explanations! This was so helpful for my understanding. Especially powerful is the language you use to describe the lifetime syntax. It might be that I need to spend more time with the book, but you make the (imo hard to translate to words in my head) syntax sound very natural in a way that emphasizes the exact guarantees you are providing when you use that syntax.

Thanks again! I say again because I often find your explanations--filled with examples and links holding troves of follow-on learning opportunities--to be super helpful.

Bobby

1 Like

I don't think that would work since what I need is either a owned value or a mutable borrow. I want to be able to modify the data underlying that I'm getting from this interface, such that when I get it again, it is changed

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.