# `return` ## Table of contents - [Overview](#overview) - [Returning empty tuples](#returning-empty-tuples) - [`returned var`](#returned-var) - [`return` and initialization](#return-and-initialization) - [Alternatives considered](#alternatives-considered) - [References](#references) ## Overview The `return` statement ends the flow of execution within a [function](../functions.md), returning execution to the caller. Its syntax is: > `return` _[ expression ]_ `;` If the function returns a value to the caller, that value is provided by an expression in the return statement. For example: ```carbon fn Sum(a: i32, b: i32) -> i32 { return a + b; } ``` When a return type is specified, a function must _always_ `return` before control flow can reach the end of the function body. In other words, `fn DoNothing() -> i32 {}` would be invalid because execution will reach the end of the function body without returning a value. ### Returning empty tuples Returning an empty tuple `()` is special, and similar to C++'s `void` returns. When a function has no specified return type, its return type is implicitly `()`. `return` must not have an expression argument in this case. It also has an implicit `return;` at the end of the function body. For example: ```carbon // No return type is specified, so this returns `()` implicitly. fn MaybeDraw(should_draw: bool) { if (!should_draw) { // No expression is passed to `return`. return; } ActuallyDraw(); // There is an implicit `return;` here. } ``` When `-> ()` is specified in the function signature, the return expression is required. Omitting `-> ()` is encouraged, but specifying it is supported for generalized code structures, including [templates](../templates.md). In order to be consistent with other explicitly specified return types, `return;` is invalid in this case. For example: ```carbon // `-> ()` defines an explicit return value. fn MaybeDraw(should_draw: bool) -> () { if (!should_draw) { // As a consequence, a return value must be passed. return (); } ActuallyDraw(); // The return value must again be explicit. return (); } ``` ### `returned var` [Local variables](../values.md#binding-patterns-and-local-variables-with-let-and-var) may be declared with a `returned` statement. Its syntax is: > `returned` _var statement_ When a variable is marked as `returned`, it must be the only `returned` value in-scope. If a `returned var` is returned, the specific syntax `return var;` must be used. Returning expressions is not allowed while a `returned var` is in scope. For example: ```carbon fn MakeCircle(radius: i32) -> Circle { returned var c: Circle; c.radius = radius; // `return c` would be invalid because `returned` is in use. return var; } ``` If control flow exits the scope of a `returned` variable in any way other than `return var;`, the `returned var`'s lifetime ends as normal. When this occurs, `return` may again be used with expressions. For example: ```carbon fn MakePointInArea(area: Area, preferred_x: i32, preferred_y: i32) -> Point { if (preferred_x >= 0 && preferred_y >= 0) { returned var p: Point = { .x = preferred_x, .y = preferred_y }; if (area.Contains(p)) { return var; } // p's lifetime ends here when `return var;` is not reached. } return area.RandomPoint(); } ``` ### `return` and initialization Consider the following common initialization code: ```carbon fn CreateMyObject() -> MyType { return ; } var x: MyType = CreateMyObject(); ``` The `` in the return statement of `CreateMyObject` initializes the variable `x` here. There is no copy or similar. It is equivalent to: ```carbon var x: MyType = ; ``` This applies recursively, similar to C++'s guaranteed copy elision. In the case where additional statements should be run between constructing the return value and returning, the use of `returned var` allows for improved efficiency because the `returned var` can directly use the address of `var` declared by the caller. For example, here the `returned var vector` in `CreateVector` uses the storage of `my_vector` for initialization, avoiding a copy: ```carbon fn CreateVector(x: i32, y: i32) -> Vector { returned var vector: Vector; vector.x = x; vector.y = y; return var; } var my_vector: Vector = CreateVector(1, 2); ``` As a consequence, `returned var` is encouraged because it makes it easier to avoid copies. > **TODO:** Have some discussion of RVO and NRVO as they are found in C++ here, > and the fact that Carbon provides the essential part of these as first-class > features and therefore they are never "optimizations" or done implicitly or > optionally. ## Alternatives considered - [Implicit or expression returns](/proposals/p0415.md#implicit-or-expression-returns) - [Named return variable in place of a return type](/proposals/p0257.md#named-return-variable-in-place-of-a-return-type) - [Retain the C++ rule](/proposals/p0538.md#retain-the-c-rule) - [Fully divorce functions and procedures](/proposals/p0538.md#fully-divorce-functions-and-procedures) ## References - Proposal [#257: Initialization of memory and variables](https://github.com/carbon-language/carbon-lang/pull/257) - Proposal [#415: Syntax: `return`](https://github.com/carbon-language/carbon-lang/pull/415) - Proposal [#538: `return` with no argument](https://github.com/carbon-language/carbon-lang/pull/538)