[Rust] _(underscore) Does Not Bind

Seung Woo Kim
CodeChain
Published in
4 min readAug 13, 2018

Rust is a language that utilizes the RAII idiom, resulting in different code depending on when the object is destroyed. For instance, let’s take a look at the code below.

This code creates an instance of Service and waits until it is terminated. This code is syntactically correct. However, if you wanted code where Service performs some action until termination, then this code is wrong. Since the Service object is not bound to any variables, this object is destroyed at the end of the second line.

If you want the Service object to stay alive until wait_for_exit is finished, you need to change the code as shown below:

In the code above, the Service object is bound to the variable service. Therefore, it waits for wait_for_exit to terminate without being extinguished, even after the end of the second line. Instead, it extinguishes when the stack is unwound when the run function ends.

However, when you compile the code above, you will see a warning that server is an unused variable. This is because the Rust compiler gives a warning if a declared variable is not used. So what if you only want to have ownership of variables that are not in use? In this case, just make the variable names start with _(underscore). Because Rust compiler treats variables that begin with _ as special, there is no compiler warning unless you actually use those variables.

So what happens if you do not give a name to a variable that you do not use? If you do not intend to use it anyway, and you only want to bind objects, couldn’t you use _ as a variable without a name, as shown in the code below?

Unfortunately, the above code does not work as expected. This is because _ does not have ownership of an object. In Rust, it is said that _ does not bind values. In other words, the code above is the same as service_run1.rs, which creates and destroys a Service object and then executes the wait_for_exit function.

In fact, this was not the intended action from the beginning. In 2013, it was reported as a bug that the value put into _ was dropped instantly, and there was a suggestion to fix _ to bind like a normal variable. In fact, making it bind is a more intuitive and general approach. However, Rust developers have specified in the specification that they do not want to bind the meaning of _. This is because there is no way to take a value and not bind it.

The property of _ not binding a value is useful in the following cases:

The code above takes a tuple and uses Option <A> first, then B. If _ had a value bound to it, then B will be moved in the fourth and fifth lines. Consequently, the eighth line would not have been compiled with a warning message that you are trying to use a moved value. However, since _does not bind values, the above code is successfully compiled.

It is important to note that it is defined for values received by _ to not be bound instead of being dropped after the statement is over. In the service_run4.rs example above, dropping a Service object is because a temporary value was not bound to it. It is not because _ dropped the value. If _ dropped the value, you will not be able to use B in the eighth line because B is dropped after the match statement in the non_bind.rs example.

Personally, the bug that caused this was the bug that took the longest time to resolve while using Rust. Because CodeChain is currently a multi-threaded program, it creates multiple services in the main thread, and each service does its job until it is terminated. At this point, most services are self-contained, so you only need to maintain objects without using them outside. Therefore, even if the variable name is _, it is compiled successfully because it is not wrong code for the compiler. In addition, in other languages, using _ as a variable is not a problem, so I never imagined it to be a problem while using rust.

This kind of bug is difficult to catch if you do not know about it, but once you understand it, it is very simple to fix. However, even Rust’s official document, “The Rust Programming Language”, only has two statement regarding this problem, saying “However, using the underscore by itself doesn’t ever bind to the value. Listing 18–22 will compile without any errors because s doesn’t get moved into _.” Since there is such little explanation, it is hard to know this concept. I hope my article will help out a fellow programmer, who decides to learn Rust, to not make the same mistakes that I have.

--

--