7

I'm learning Rust and I've found something confusing with functions. According to the official reference, a return expression:

.. [is] denoted with the keyword return. Evaluating a return expression moves its argument into the output slot of the current function, destroys the current function activation frame, and transfers control to the caller frame.

So, this program works:

fn main() {
    let current_hour = 10;
    let message = get_message(current_hour);

    println!("Good {0}", message);
}

fn get_message(current_hour: i32) -> &'static str {

    if current_hour < 11 {
        return "Morning"
    }
    else if current_hour < 17 {
        return "Afternoon"
    }
    else {
        return "Evening"
    }

}

And when I add semi-colons to the "return" expressions, it still works:

fn main() {
    let current_hour = 10;
    let message = get_message(current_hour);

    println!("Good {0}", message);
}

fn get_message(current_hour: i32) -> &'static str {

    if current_hour < 11 {
        return "Morning";
    }
    else if current_hour < 17 {
        return "Afternoon";
    }
    else {
        return "Evening";
    }

}

My understanding of expression statements (e.g. expr;) is that it will evaluate the expr expression, and ignore the result (instead it will use ()). In the case of using return expr;, there doesn't seem to be a reason for using ; since return expr destroys the current function activation frame (and would then ignore the ;).

So, why does a lot of Rust code that I've seen use the semi-colon if it's not necessary (and in fact makes learning about Rust's functions very confusing... since it feels like it's contradictory). Is it just an idiom from other languages that has carried over?

E_net4
  • 27,810
  • 13
  • 101
  • 139
TheCloudlessSky
  • 18,608
  • 15
  • 75
  • 116
  • Those `;` are required in C/C++/Java/Perl and probably a few more. – Mat Jan 10 '15 at 13:17
  • 1
    @Mat - Of course! But, in Rust, you can use the last line to return a value *without* an explicit `return`... and you don't use a semicolon because it would evaluate the expression and return `()`. Check out the [official book](http://doc.rust-lang.org/book/functions.html) to see what I mean. It just seems inconsistent... – TheCloudlessSky Jan 10 '15 at 13:26
  • What seems inconsistent? That there is no semicolon when just writing the return value, but (by convention) a semicolon when using `return`? –  Jan 10 '15 at 13:39
  • 1
    @delnan - Yes. It's confusing when learning that `;` causes the function to return `()`... except where you've used `return expr;`. – TheCloudlessSky Jan 10 '15 at 13:51
  • @TheCloudlessSky `;` doesn't cause functions to return `()`, it delimits statements. Although it's technically an expression, I consider `return` a statement (the only difference to just writing the return value is the effect on control flow), so of course it's going to get a semicolon. –  Jan 10 '15 at 13:57
  • 1
    @delnan The [official book](http://doc.rust-lang.org/book/functions.html) disagrees with you: "Our function claims to return an i32, but with a semicolon, it would return () instead." Also, there are plenty of uses where the semicolon is omitted (e.g. [the official time crate](https://github.com/rust-lang/time/blob/7f105d4dd2bde23d4b8516dc02566cfc46b60b22/src/lib.rs#L241)). – TheCloudlessSky Jan 10 '15 at 14:05
  • In fact, `fn foo() -> () { ; }` compiles and runs as expected. – TheCloudlessSky Jan 10 '15 at 14:10
  • 1
    @TheCloudlessSky The semicolon turns `x + 1` into a statement, and statements evaluate to `()`. So in that sense, a semicolon turns what would be a return value into `()`, but IMHO that's not the best way to think about it, certainly not *for all semicolons everywhere*. As for the `time` crate: The AFAIK more common [convention](http://aturon.github.io/style/braces.html), though not officially blessed by an RFC, are semicolons on `return`s. –  Jan 10 '15 at 14:15

1 Answers1

6

Is it just an idiom from other languages that has carried over?

Yes, I think that's it, just habit and possibly a general sense of aesthetics about what feels weird and what doesn't (which is of course influenced by someone's previous languages).

AFAICT, the only difference it can make is for something like

fn foo() {
    return;
    println!("hi");
}

where return needs to be a statement... but the code after the return is unreachable (which the compiler will tell you), so this likely doesn't occur that much in real code.

huon
  • 94,605
  • 21
  • 231
  • 225