Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The return statement is a control flow construct that immediately terminates the execution of the current function and passes control, along with an optional evaluated expression, back to the calling context.

Syntax

return [expression];

Mechanics and Compiler Rules

Type Conformance In standard synchronous functions, the evaluated type of the expression must be statically assignable to the declared return type of the enclosing function. Under Dart’s sound type system, returning a type that does not conform to the function signature results in a compile-time error.
int calculateValue() {
  return 42; // Valid: 42 is statically assignable to int
}
Behavior in Asynchronous Functions In functions marked with the async modifier, the return statement automatically wraps the evaluated expression in a Future. Because of this, the standard static assignability rule is relaxed: if an async function has a declared return type of Future<T>, the return expression can be of type T. Dart will automatically wrap the value T into a completed Future<T>. Furthermore, if the returned expression is itself a Future<T>, Dart flattens the return value to prevent nested futures (e.g., avoiding Future<Future<T>>).
Future<String> fetchData() async {
  return "Data"; // Valid: String is automatically wrapped in Future<String>
}
Void Functions Functions declared with the void type indicate that the caller should ignore the return value. Within a void function, an empty return; statement can be used to terminate execution. A return statement in a void function can also be followed by an expression, provided the expression’s static type is void or Never. Returning any other type (including dynamic) from a void function results in a compile-time error.
void process() {
  if (false) return; // Valid: Empty return terminates execution
  return print('done'); // Valid: print() has a static return type of void
}
Implicit Returns In modern Dart with sound null safety, reaching the end of a function block without encountering a return statement causes the function to implicitly return null. However, the compiler strictly restricts which functions are allowed to complete normally. If a function reaches the end of its block but its signature does not permit it, the compiler emits a body_might_complete_normally (or body_might_complete_normally_nullable) error. A function is allowed to complete normally without an explicit return only if:
  1. It is a standard synchronous function with a declared return type of void, dynamic, FutureOr<void>, or FutureOr<dynamic>.
  2. It is an async function with a declared return type of void, dynamic, Future<void>, Future<dynamic>, FutureOr<void>, or FutureOr<dynamic>.
  3. It is a generator function (sync* or async*), regardless of its declared return type (e.g., Iterable<int> or Stream<String>), because reaching the end simply terminates the generator.
Functions with a declared return type of Null (or Future<Null>) are not permitted to complete normally and must explicitly return null;.
import 'dart:async';

// Valid: Implicitly returns null (dynamic return type)
dynamic getDynamicValue() {
  // No explicit return statement needed
}

// Valid: Implicitly returns a Future completing with null
Future<void> processAsync() async {
  // No explicit return statement needed
}

// Valid: Fire-and-forget async function completing normally
void fireAndForget() async {
  // No explicit return statement needed
}

// Valid: Implicitly returns null
FutureOr<void> processFutureOr() {
  // No explicit return statement needed
}

// Valid: Generator completes normally, closing the iterable
Iterable<int> getNumbers() sync* {
  yield 1;
  // No explicit return statement needed
}

// Invalid: Compile-time error (body_might_complete_normally_nullable)
// Null getNullValue() {
//   // Fails to compile: must explicitly return null;
// }
Arrow Syntax Shorthand Dart provides the => (fat arrow) operator as a lexical shorthand for functions containing a single return statement. The expression following the arrow is automatically evaluated and returned.
// Standard syntax
bool isEven(int a) {
  return a % 2 == 0;
}

// Arrow syntax equivalent
bool isEvenArrow(int a) => a % 2 == 0;
Behavior in Generators In generator functions (sync* for Iterable and async* for Stream), the return statement does not emit a value to the sequence. Instead, it immediately terminates the generator, closing the underlying iterator or stream. Values in these functions must be emitted using yield or yield*, while return is strictly used for early termination.
Iterable<int> generateNumbers() sync* {
  yield 1;
  return; // Terminates the generator; no further values are yielded
}
Master Dart with Deep Grasping Methodology!Learn More