Refactoring will spoil volatile debt - why?
I'm trying to figure out why the following refactoring results in an error, even though it should effectively have the same behavior:
Before:
fn req_handler(req: &mut Request) -> IronResult<Response> { let pool = req.get::<Read<Database>>().ok().expect("database component not initialised"); let connection = pool.get().unwrap(); let maybe_id = req.extensions.get::<Router>().unwrap().find("id"); ...
After:
pub fn get_pool_connection<'a, 'b, 'c>(req: &'a mut Request<'b, 'c>) -> PooledConnection<'a, PostgresConnectionManager> { let pool = req.get_ref::<Read<Database>>().ok().expect("database component not initialised"); pool.get().unwrap() } fn req_handler(req: &mut Request) -> IronResult<Response> { let connection = get_pool_connection(req); let maybe_id = req.extensions.get::<Router>().unwrap().find("id");
This results in an error:
src/main.rs:64:20: 64:34 error: cannot borrow `req.extensions` as immutable because `*req` is also borrowed as mutable
src/main.rs:64 let maybe_id = req.extensions.get::<Router>().unwrap().find("id");
^~~~~~~~~~~~~~
src/main.rs:62:42: 62:45 note: previous borrow of `*req` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `*req` until the borrow ends
src/main.rs:62 let connection = get_pool_connection(req);
^~~
src/main.rs:76:2: 76:2 note: previous borrow ends here
src/main.rs:61 fn req_handler(req: &mut Request) -> IronResult<Response> {
...
src/main.rs:76 }
So the problem is that the get_pool_connection
request is borrowed and returned connection
, which prevents further use req
. But why is this happening? req
guaranteed to use at least the same lifetime as the returned one PooledConnection
. He didn't move either, he just passed on like &mut
. So what's stopping you from using a query?
And why does the error say it *req
was borrowed when both the local req
and the function parameter are references?
source to share
This is actually exactly the meaning of life annotations. If you have a function that has this prototype:
fn get_bar<'a>(&'a Foo) -> Bar<'a> { ... }
This means that the returned object Bar
has a resource bound to one of the objects Foo
. Consequently:
- Objects
Bar
borrow the objectFoo
while it is alive. - The object is
Bar
not allowed to survive the objectFoo
.
In your case connection
has a type PooledConnection<'a, ...>
, where 'a
is the lifetime defined in &'a mut req
, so it is treated as mutable borrowing req
.
It worked before the refactoring because the lifetime is connection
actually related to the lifetime pool
, which did not take req
since it does not contain any lifetime parameter.
How do your refactoring forces connection
borrow req
that weren't needed before, it might not be appropriate refactoring.
source to share