Rust Notes on Temporary values (usage of Mutex) - 1
Tags: rust
Published: 2023-06-14 04:20:53

---
title: Rust Notes on Temporary values (usage of Mutex) - 1
published: true
description: A collection of notes I have made, while learning Rust
tags: #rust
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fieo0rdpxxt5daynrb4i.jpg
# Use a ratio of 100:42 for best results.
# published_at: 2023-06-14 04:20 +0000
---

[Cover image credit: https://pixabay.com/users/engin_akyurt-3656355]

### The build up

Just like other enthusiastic Rust newbies, I am trying to trek through the difficult terrain of Rust's Borrow-checker, with excitement,  mixed with trepidation. Many times, I fall foul of the compiler, because I am careless or I lose sight of the obvious. But, some other times, compiler's reprimands baffle me, to no end.

One such case is of compiler flagging: temporary values getting freed at the end of the statement! 

A method-call expression like:

```rust
a.b().c().d;
```
is so common in a program that one tends to write it, almost by reflex. Yet, some times the compiler derails the line of thought, unexpectedly, pointing out release of a temporary variable, that one hasn't even mentioned.

I had decided to understand the whys and the wherefores of this particular problem, to reasonably good extent. At least, I should know how to avoid those. This is a digest of that exploration.

### Simulate the error 


An `Employee` has an id ( `i32` ). It implements a `get_details()` method.

This method, intentionally, returns a new `Details` Object (the reason behind this, will be clearer later). The object initializes the `name` field with a String constant, which it *owns*!

```rust
#[derive(Debug)]
struct Employee {
    id: i32
}

#[derive(Debug)]
struct Details {
    emp_id: i32,
    name: String
}

impl Employee {
    pub fn get_details(&self) -> Details {
        Details { emp_id: self.id, name: String::from("Nirmalya") }
    }
}

impl Details {
    pub fn get_name( &self ) -> String {
        self.name
    }
}

fn main() {

    let e = Employee { id: 10 };
    let n = e.get_details().get_name();
    println!("Employee name: {}", n);     

}
```

The compiler frowns, expectedly ...

```bash
error[E0507]: cannot move out of `self.name` which is behind a shared reference
  --> src/main.rs:31:9
   |
31 |         self.name
   |         ^^^^^^^^^ move occurs because `self.name` has type `String`, which does not implement the `Copy` trait
```
We are not allowed to 'move' the name here; the `&self` parameter is prohibiting it. The move requires the `Details` to be modified. The `get_details()` method taken in an immutable reference: `&self`. After the method returns, `self.name` cannot remain uninitialized.

We cannot move but we can possibly share a reference then?

```rust
impl Details {
    pub fn get_name( &self ) -> &String {  // String is replaced with &String
        &self.name
    }
}
```

The compiler finds the temporary which is freed prematurely, this time.

```bash
error[E0716]: temporary value dropped while borrowed
  --> src/main.rs:41:13
   |
41 |     let n = e.get_details().get_name();
   |             ^^^^^^^^^^^^^^^           - temporary value is freed at the end of this statement
   |             |
   |             creates a temporary value which is freed while still in use
42 |
43 |     println!("Employee name: {}", n);     
   |                                   - borrow later used here
   |
help: consider using a `let` binding to create a longer lived value
   |
41 ~     let binding = e.get_details();
42 ~     let n = binding.get_name();
   |

For more information about this error, try `rustc --explain E0716`.
```

So, changing the body and return type of `Details::get_details()` is causing an otherwise harmelss method-call expression to fail. 

But why? Let's find out more about this.

### Elaboration

A binding comes into existence with the `let` statement: `e` is bound to and thereby is owning an `Employee` struct(ure).

```rust
let e = Employee { id: 10 };
```

We are trying get an access to the Employee's name. This __name__ is not a part of `Employee` but of a different object of type `Details`. 
```rust
let n = e.get_details().get_name();
```
What `get_details()` produces is a `Details` object. We are calling `get_name()` on it. What's there to complain about?

Well, the `get_name()` is returning a reference to a member variable of `Details`. For this reference to remain valid (pointing to some place which is initialized with some known value), `Details` has to keep existing. But, till when? The answer lies in establishing its *scope*.

### Expresssions and Scopes

This is a method-call [expression]([https://](https://doc.rust-lang.org/stable/reference/expressions/method-call-expr.html)):
```rust
e.get_details().get_name();
```

`get_details()` is a direct method on the type `Employee`. Here, `e` is called the receiver of method-call.

`get_name()` is a direct method on the type `Details`. But, where is the receiver of this method-call? Taking a closer look, we find that an unnamed object of type `Details` has been made available - *temporarily* - so that we can call the method. Our intention is to be able to get hold of what `get_name()` returns. We don't really care about this faceless helper object, though. 

The key understanding here, is that `get_name()` returns a **reference**. It refers to a field of `Details` object. If and when this (temporary) `Details` object ceases to exist (or _Drop_-ped, if you like), the reference is invalidated. 

By the rule of scope of such temporaries ([more here]([https://](https://doc.rust-lang.org/stable/reference/expressions.html?highlight=temporary#temporaries))), they can live till the end of the statement that contains the call that produces it. Interpeting this vis-a-vis our example,  by the time the whole expression is evaluated and the statement ends, the faceless `Details` object has gone out of existence. Therefore, it is illegal to hold a reference to a field that it owns. So, `n` cannot be assigned to.


This explains the complaint from the compiler, shown above.

### Going a little further

One way, not to let the faceless `Details` object go, is to bind it to a memory location. 

```rust
fn main() {
    let e = Employee { id: 10 };
    let intermediate_d = e.get_details(); // <--- Binding!
    let n = intermediate_d.get_name();    // <--- Method call expression
    println!("Employee name: {}", n);     
}
```
In this case, the compiler is happy and waves us ahead. But, why exactly?
Because we have bound the hitherto faceless `Details` object to `intermediate_d`, its scope has now been extended to the end of the block it belongs to (in this case, the end of the body of function, i.e.,`main()`). Thus, getting hold of the `name` inside it, is not illegal anymore.

This was what the ever helpful Rust compiler suggested in the error message, shown earlier! :ok_hand: :star2:

Interestingly, the following code is flagged as alright, by the compiler.
```rust
fn main() {
    let e = Employee { id: 10 };
    let n = e.get_details().get_name().len(); // <-- expression produces a value.
    println!("Employee name: {} chars long", n);     
}
```
In this case, the length of the name is what we hold in `n`. The faceless `Details` object, goes away by the end of the statement, but it doesn't matter. We are not holding any reference to `Details.name` anyway.

Even this works, but for a slightly different reason:

```rust
impl Details {
    pub fn get_name( &self ) -> String {
        self.name.to_owned()  // <-- Not a reference, but a cloned value, unassociated with `self.name`
    }
}
// ........
fn main() {
    let e = Employee { id: 10 };
    let n = e.get_details().get_name();
    println!("Employee name: {}", n);     
}
```
Because `get_name` returns a value that is owned by - and not referred to by - the caller, the non-existence of the faceless `Details` object is immaterial here. `n` is bound to a fresh replica of what was held by `Details.name`. Its scope extends till the end of the block; in this case, the end of body of function, i.e., `main()`.

### Main Takeaways

* Method chains are *Method-call expressions*. Like every expression, they evaluate to a value.
* Every  dot ( . ) operation is a method/function, which operates on an object, called the 'Receiver' according to the Book (rust book). The receiver's type must have that method defined on itself.
* In some cases, in order to determine the intended receiver, the compiler follows the references along the expression and produces temporary objects as receivers. The scope of these temporary objects extends up to the end of the statement they are contained in (not exactly, but let's continue till subsequent articles on this topic). Therefore, the compiler considers any attempt to access these temporary objects through references, after the statement, as illegal.
* The simplest way to avoid this, is to declare local variables to bind to these temporary objects. The helpful compiler even hints at this, along with the error message.

## Acknowledgements

In my quest to understand the behaviour of the compiler in this case, I have gone through a number of articles / blogs / explanations. I will be unfair and utterly discourteous on my part, if I don't mention at least, some of them. This blog stands on the shoulders of those authors and elaborators:
* https://fasterthanli.me/articles/a-rust-match-made-in-hell from one of the most readable and elucidative take on all things Rust, by Amos ( @fasterthanlime ).
* A brief yet illuminative [answer]([https://](https://stackoverflow.com/questions/72777453/mutex-locking-inside-loop-declaration)) by Sven [Marnach]([https://](https://stackoverflow.com/users/279627/sven-marnach)) on Stackoverflow.
* An useful question on Stackoverflow by [Bosh](https://stackoverflow.com/users/318206/bosh) and fantastic answer by Jim [Blandy](https://stackoverflow.com/users/406309/jim-blandy). This answer has brought forth that **Aha** moment for me but the discussion trail itself is very helpful (thanks everyone else, in that ticket).
* The chapter on *Destruction* in the Rust [wiki](https://rustwiki.org/en/reference/destructors.html#destructors) and a bit of my own expeimentation  
* An old but quite useful explanation of [scoping]((https://vojtechkral.github.io/blag/rust-drop-order/)); recommended!
* Of course, the relevant [pages](https://rustwiki.org/en/reference/destructors.html#temporary-scopes) of The Rust Wiki, an excellent aid for a newbie like me.
* My companion [book](https://www.oreilly.com/library/view/programming-rust-2nd/9781492052586/) by Jim Blandy (again!), Jason Orendorff, Leonora Tindall