Start learning free

LESSON 49 OF 414 · FUNCTIONS I

Code After return in Rust: What Gets Printed?

Quiz Read the full explanation

Quiz: What would this code produce if we were to copy-paste it in a code editor and run it?

fn greet_and_return() -> String {
    return "How are you doing?".to_string();
    println!("Hey bro!");
}

fn main_function() {
    let question = greet_and_return();
    println!("{}", question);
}

Important Note:

Do not use an actual code editor to get the answer! It would defy the whole purpose of the quiz!

Pick your answer

Next lesson

RUST · FUNCTIONS I

Quiz Return 7 in Rust, explained

Problem overview

This quiz shows a function that has a line after its return, and asks what the program prints:

fn greet_and_return() -> String {
    return "How are you doing?".to_string();
    println!("Hey bro!");
}

fn main_function() {
    let question = greet_and_return();
    println!("{}", question);
}

The four options differ in which lines appear and in what order. A prints Hey bro! and then How are you doing?. B prints only How are you doing?. C prints How are you doing? and then Hey bro!. D prints only Hey bro!. You answer by assigning a letter to answer.

Approach: run it line by line

Trace the program in the order the computer executes it, not the order in which things look important.

  1. main_function calls greet_and_return(). Execution jumps into that function.
  2. The first line is return "How are you doing?".to_string();. This creates an owned String, ends the function on the spot, and hands the string back.
  3. The line println!("Hey bro!"); is never reached. Execution has already left the function.
  4. Back in main_function, question receives "How are you doing?".
  5. The last line prints question.

The only output is therefore:

How are you doing?

That is option B. Options A and C need the println!("Hey bro!") to run, and option D needs it to run without the other line. None of that can happen.

Does it compile?

Yes. A function whose body ends after a return has nothing left to produce, so the unreachable println! doesn't upset the -> String signature. The compiler does notice the dead line and prints a warning:

warning: unreachable statement
  any code following this expression is unreachable

A warning doesn't stop the build. It is the compiler pointing at code that can never run, which is usually a sign that something is in the wrong place.

The solution in Rust

let answer: String = "B".to_string();

The literal "B" has type &str, a borrowed piece of text. Calling to_string() makes an owned String from it, which is what the annotation : String asks for.

Why return ends a function immediately

return means "leave this function now and give this value to the caller". Rust does not run the remaining lines of the function afterwards. A function can have several return statements, usually guarded by an if, and the first one reached wins:

fn describe(n: i32) -> String {
    if n < 0 {
        return "negative".to_string();
    }
    println!("checked {}", n);
    "not negative".to_string()
}

Calling describe(-5) returns negative and never prints checked. Calling describe(7) skips the if, prints checked 7 and returns not negative.

Compare this with leaving the value as the final expression of the function. These two functions behave the same:

fn a() -> String {
    return "same".to_string();
}

fn b() -> String {
    "same".to_string()
}

The second form has no return and no semicolon, so the value of the last expression is returned. Either way, code that comes after the point where the value is produced doesn't help the function print anything, so work to be done before returning must be written before it.

Getting both lines out

If the goal were to see Hey bro! first and How are you doing? second, the order inside the function has to change: print first, then return.

fn greet_and_return() -> String {
    println!("Hey bro!");
    return "How are you doing?".to_string();
}

Now Hey bro! is printed while the function runs, and How are you doing? is printed afterwards by main_function, because it prints the returned value. This is option A, and the contrast with the quiz's code shows why the order of the two lines decides the answer.

Common mistakes

  • Reading the function as "print, then return". The lines run in the order written, and the return comes first.
  • Thinking the leftover line runs "after the function finishes". Statements after a return in the same block are never run at all.
  • Expecting the compiler to reject dead code. It only warns.

Key takeaways

  • A return ends the function at once; any statement below it in the same block is unreachable.
  • The compiler warns about unreachable statements but still builds the program.
  • To print before returning, put the println! above the return.
Keep going with RustAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
Start learning free