Return value

On this page 7

A return value is the result that a function passes back to the code that called it when the function finishes executing. In programming fundamentals, the return value is the main way a function delivers its output: the caller supplies inputs through parameters, and the function answers with a value that can be stored in a variable, passed to another function or used in an expression.

Return values make functions composable, because the output of one call can become the input of the next. How a language types, transfers and signals failure through return values strongly shapes the style and reliability of the code written in it.

How a function returns a value

A function returns a value by executing a return statement, which ends the function immediately and transfers both control and the result to the caller. Any code after an executed return statement in the same path does not run, which is why an early return is a common way to handle special cases at the top of a function.

At the machine level, the calling convention of the platform decides where the result travels. Small values such as integers and pointers usually pass through a CPU register, for example RAX on x86-64 or x0 on 64-bit ARM, while larger structures are written to memory reserved by the caller. The function’s stack frame is then removed, so a function must never return a pointer or reference to its own local variable in languages with manual memory management.

Languages differ in what happens when no explicit value is returned. The table below summarizes the default behavior in several common languages.

LanguageDefault resultNotes
PythonNoneEvery function returns something
JavaScriptundefinedArrow functions with an expression body return it implicitly
C and C++Nothing for void functionsMissing return in a non-void function is a serious error
RustValue of the final expressionUnit type () when there is no final expression
JavaNothing for void methodsCompiler rejects a missing return in non-void methods
Default result when a function ends without an explicit value

Forms of return values

Return values come in several forms that differ in what they communicate to the caller. Choosing the right form is part of designing a clear function interface.

FormExampleTypical use
Single valueAn integer, string or objectOrdinary computation results
Multiple valuesA tuple, as in Python or GoResult plus extra information
Optional valueOption or Optional typeResult that may legitimately be absent
Result or error typeResult in Rust, value and error pair in GoOperations that can fail
Status code0 for success, nonzero for failureC libraries and process exit codes
Future or promiseA value delivered laterAsynchronous operations
Common forms of return values

In statically typed languages, the return type is part of the function signature and is checked by the compiler. In dynamically typed languages, type hints or annotations document the intended return type, and static analysis tools can verify them before the program runs.

Return values compared with other ways to deliver results

A return value is only one of several channels a function can use to produce an effect. Functions can also modify arguments, change shared state or raise an exception, and each channel has different consequences for readability and testing.

MechanismHow it worksMain drawback
Return valueResult handed back explicitlyCaller may ignore it
Output parameterFunction writes into a caller’s variable or referenceLess obvious data flow
Global or shared stateFunction changes data visible elsewhereHidden coupling, hard to test
ExceptionFunction aborts and signals an errorControl flow jumps out of sight
CallbackFunction passes the result to another functionNesting and harder tracing
Ways a function can communicate results

Functions that communicate only through parameters and return values, with no side effects, are called pure functions. They always return the same value for the same inputs, which makes them easy to test, cache and run in parallel.

Designing good return values

A good return value is predictable, consistently typed and impossible to misunderstand. A function that sometimes returns a list and sometimes returns a number forces every caller to check the type before using it.

  • Return one consistent type, using an optional or result type to express absence or failure.
  • Prefer an empty collection to a null value when there are simply no results, so callers can loop without extra checks.
  • Return named structures instead of long tuples when more than two or three values are involved.
  • Avoid returning internal mutable state directly, because callers could modify the object behind the function’s back.
  • Mark important results as must-use where the language allows it, for example with the nodiscard attribute in C++ or must_use in Rust.

Common mistakes with return values

Most defects related to return values come from results that are ignored, missing or ambiguous. The table lists frequent symptoms and their causes.

SymptomCauseFix
Unexpected None or undefinedA code path has no return statementReturn explicitly on every path
Silent failureError code returned but never checkedUse result types or must-use warnings
Crash on dangling pointerReference to a local variable returnedReturn by value or allocate safely
Wrong sentinel interpreted as dataValue such as -1 is also a valid resultUse an optional type instead
Original list unchangedIn-place method returns None, as with sort in PythonUse the returning variant, such as sorted
Return value mistakes and fixes

The short version

A return value is the answer a function gives back. You hand a function some information, it does its job, and it gives you a result.

It works like ordering at a counter. You give the order, the kitchen prepares it, and the meal handed back to you is the return value. You can eat it, share it or use it as part of something bigger. If the kitchen hands back nothing, you have nothing to work with.

Where it makes a difference

A developer writes a function that looks up a customer’s discount in a database. The first version returns -1 when the customer is not found and the discount percentage otherwise. Months later, another part of the system applies a returned value of -1 as a negative discount and overcharges several orders.

The team redesigns the function to return an optional discount: either a percentage or an explicit absence. The type checker now forces every caller to handle the missing case, and a test confirms that unknown customers receive no discount.

The outcome is that the same mistake can no longer compile or pass static checks. A single change in the return value design removed a whole category of silent pricing errors.