# 2.2 Function return values
> Rust return types, tail expressions as return values, the return keyword, and the missing-semicolon error every beginner meets.
Source: https://learnrust.net/chapter-2/return-values/
The functions in the last lesson could *act*, but everything they computed died with them. To participate in their caller's work, functions need to hand values back. In Rust, this is where lesson [1.11](@/chapter-1/expressions-and-statements.md) stops being theory.
## Return types and return values
A function that produces a value declares the value's type after an arrow:
```rust
fn five() -> i32 {
5
}
fn main() {
let x = five();
println!("{}", x + 2);
}
```
```
7
```
`-> i32` says "calling this function yields an `i32`," and the call expression `five()` evaluates to that value wherever it appears: initializing a variable, sitting inside arithmetic, anywhere an `i32` could go.
Now the part Rust does differently, and better. Where's the `return` keyword? Not needed: a function body is a **block**, and you already know blocks evaluate to their tail expression. `5` has no semicolon, so it's the tail, so it's the function's value. The 1.11 rule and the function rule are the *same rule*. A more useful specimen:
```rust
fn get_number() -> i32 {
let mut input = String::new();
std::io::stdin()
.read_line(&mut input)
.expect("failed to read input");
input.trim().parse().expect("that wasn't a whole number")
}
```
Statements first, then the tail expression delivers the goods. (Two small notes: `std::io::stdin()` is the long-form spelling that skips the `use` line, handy in snippets; and `parse` knows to produce an `i32` here because the function's return type says so. Inference reaching *that* far is very Rust.)
## The error you're guaranteed to meet
Because the tail expression does the returning, one reflexive semicolon changes everything:
```rust
fn double(x: i32) -> i32 {
x * 2;
}
```
```
error[E0308]: mismatched types
--> src/main.rs:1:22
|
1 | fn double(x: i32) -> i32 {
| ------ ^^^ expected `i32`, found `()`
| |
| implicitly returns `()` as its body has no tail or `return` expression
2 | x * 2;
| - help: remove this semicolon to return this value
```
Decode it with your 1.11 knowledge: the semicolon discarded `x * 2`, the body became all-statements, all-statement blocks evaluate to `()`, and the function promised an `i32`. The compiler knows this mistake so well that the help line is surgical: *remove this semicolon*. You will make this typo within days; now it costs you four seconds.
## The return keyword
Rust does have `return`, for exiting *before* the end:
```rust
fn classify(n: i32) -> i32 {
if n < 0 {
return -1;
}
n * 10
}
```
(A sneak preview of `if`, formally lesson 4.7.) For a negative `n`, the function exits immediately with -1; otherwise it falls through to the tail expression.
{% callout(kind="best", title="Best practice") %}
Use the tail expression for a function's normal result, and `return` only for early exits. `return n * 10;` as a final line works, but it reads as an accent; idiomatic Rust ends on the bare expression, and rustfmt-formatted code from the ecosystem will train your eye to expect it.
{% end %}
## Functions that return nothing
No arrow means the function returns `()`, the unit type, like `print_warning` last lesson and like `main` itself. Such functions exist for their side effects. You *can* write `-> ()` explicitly; nobody does.
One consequence worth a sentence: since `main` returns `()`, your program signals "success" to the operating system automatically when `main` ends. Programs that need to signal failure get their tools in lessons 7.8 and 12.3.
And one warning genre to recognize, when `return` and trailing code mix:
```rust
fn answer() -> i32 {
return 42;
println!("this line is beyond the end of the world");
}
```
```
warning: unreachable statement
--> src/main.rs:3:5
|
2 | return 42;
| --------- any code following this expression is unreachable
3 | println!("this line is beyond the end of the world");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable statement
|
= note: `#[warn(unreachable_code)]` (part of `#[warn(unused)]`) on by default
```
It compiles, the doomed line never runs, and the compiler tells you so. Code after a `return` is a fossil; delete it or move it above.
## The payoff: don't repeat yourself
Remember the chapter 1 finale, with its input-reading recipe pasted twice? Functions retire that duplication:
```rust
fn main() {
println!("Enter a whole number:");
let x = get_number();
println!("Enter another whole number:");
let y = get_number();
println!("{} + {} is {}", x, y, x + y);
}
fn get_number() -> i32 {
let mut input = String::new();
std::io::stdin()
.read_line(&mut input)
.expect("failed to read input");
input.trim().parse().expect("that wasn't a whole number")
}
```
```
Enter a whole number:
6
Enter another whole number:
4
6 + 4 is 10
```
The recipe now exists in exactly one place. If it needs improving (and chapter 12 will improve it), there's one place to improve. Programmers call this the **DRY** principle: Don't Repeat Yourself. Its violation has a name too (WET, "write everything twice"), which tells you how the industry feels about it.
## Quiz time
**Question #1**
What does this program print?
```rust
fn seven() -> i32 {
7
}
fn main() {
println!("{}", seven() + seven());
}
```
Show solution
```
14
```
Each call evaluates to 7, and the call expressions participate in arithmetic like any other values.
**Question #2**
Predict the compiler's reaction (error or warning, and roughly what it says):
```rust
fn area() -> i32 {
6 * 7;
}
fn main() {
println!("{}", area());
}
```
Show solution
Error E0308, mismatched types: the function promises `i32` but the semicolon discards `6 * 7`, so the body evaluates to `()`. The help line says to remove the semicolon. (If you said "expected i32, found ()", full marks.)
**Question #3**
A function ends with these two lines. What does the compiler say, and does the program run?
```rust
return total;
println!("done!");
```
Show solution
It compiles and runs; the `println!` never executes, and the compiler issues an "unreachable statement" warning pointing at it. The `return` above it ends the function every time.
Returning values is half of a function's plumbing. The other half flows the opposite way: getting values *in*. Parameters, next.