# The `return` Keyword

### Return Values

Functions often need to produce results.

A function may calculate something, create data, search for information, or transform input into output. The result comes back to the caller through a return value.

A simple example:

```zig
fn add(a: i32, b: i32) i32 {
    return a + b;
}
```

This function:

- receives two integers
- adds them
- returns the result

The return type appears after the parameter list:

```zig
i32
```

meaning the function returns a signed 32-bit integer.

## The `return` Keyword

The `return` keyword immediately exits the function and sends a value back to the caller.

Example:

```zig
fn square(x: i32) i32 {
    return x * x;
}
```

Calling it:

```zig
const result = square(5);
```

After execution:

```text
result = 25
```

The function runs:

```zig
x * x
```

then returns the computed value.

## Understanding Function Flow

When a function is called, execution temporarily jumps into the function.

Example:

```zig
fn multiply(a: i32, b: i32) i32 {
    return a * b;
}
```

Call:

```zig
const value = multiply(3, 4);
```

Flow:

```text
main
  -> multiply(3, 4)
       -> return 12
  <- back to main
```

The returned value becomes the result of the function call.

## Returning Different Types

Functions can return many kinds of values.

## Returning Integers

```zig
fn getScore() i32 {
    return 100;
}
```

## Returning Floating Point Values

```zig
fn pi() f64 {
    return 3.1415926535;
}
```

## Returning Booleans

```zig
fn isEven(value: i32) bool {
    return value % 2 == 0;
}
```

Calling:

```zig
const result = isEven(10);
```

Result:

```text
true
```

## Returning Strings

Strings are usually slices.

```zig
fn getName() []const u8 {
    return "Zig";
}
```

Calling:

```zig
const name = getName();
```

## Returning Structs

Functions can return complex data structures.

Example:

```zig
const Point = struct {
    x: i32,
    y: i32,
};

fn createPoint() Point {
    return Point{
        .x = 10,
        .y = 20,
    };
}
```

Calling:

```zig
const p = createPoint();
```

Now:

```text
p.x = 10
p.y = 20
```

This is common in Zig programs.

## Returning Arrays

Functions can return arrays.

```zig
fn makeArray() [3]i32 {
    return [3]i32{ 1, 2, 3 };
}
```

Calling:

```zig
const numbers = makeArray();
```

Result:

```text
[1, 2, 3]
```

## Returning Early

`return` exits immediately.

Example:

```zig
fn check(value: i32) i32 {
    if (value < 0) {
        return 0;
    }

    return value;
}
```

Calling:

```zig
check(-5);
```

Flow:

```text
value < 0
return 0
```

The second return never executes.

This pattern is extremely common.

## Multiple Return Paths

Functions may return from different branches.

Example:

```zig
fn max(a: i32, b: i32) i32 {
    if (a > b) {
        return a;
    }

    return b;
}
```

Calling:

```zig
const result = max(10, 30);
```

Result:

```text
30
```

Each path must return the correct type.

## Void Return Type

Some functions do not return values.

These use `void`.

Example:

```zig
fn printMessage() void {
    std.debug.print("Hello\n", .{});
}
```

The function performs an action but returns nothing.

Calling:

```zig
printMessage();
```

You cannot store the result because there is no result.

Incorrect:

```zig
const x = printMessage();
```

## Implicit vs Explicit Returns

Zig requires explicit `return`.

This is invalid:

```zig
fn add(a: i32, b: i32) i32 {
    a + b;
}
```

Correct:

```zig
fn add(a: i32, b: i32) i32 {
    return a + b;
}
```

This design makes control flow easier to read.

Nothing is hidden.

## Returning Error Unions

Many Zig functions may fail.

These functions return error unions.

Example:

```zig
fn divide(a: f64, b: f64) !f64 {
    if (b == 0) {
        return error.DivisionByZero;
    }

    return a / b;
}
```

The return type:

```zig
!f64
```

means:

- either an `f64`
- or an error

Calling:

```zig
const result = try divide(10, 2);
```

This topic becomes very important later in Zig.

## Returning Optionals

Functions may also return optional values.

Example:

```zig
fn find(value: i32) ?i32 {
    if (value == 10) {
        return 10;
    }

    return null;
}
```

The type:

```zig
?i32
```

means:

- either an `i32`
- or `null`

Optionals are Zig’s way of representing “maybe there is a value.”

## Named Result Variables

Zig also allows named return variables.

Example:

```zig
fn add(a: i32, b: i32) i32 {
    const result = a + b;

    return result;
}
```

This can improve readability when computations are more complex.

## Returning Pointers

Functions may return pointers.

Example:

```zig
fn getPointer(value: *i32) *i32 {
    return value;
}
```

But pointer lifetimes matter.

Dangerous example:

```zig
fn badPointer() *i32 {
    var x: i32 = 10;

    return &x;
}
```

This is invalid because `x` disappears after the function ends.

Returning pointers safely is an important topic in systems programming.

## Return Type Checking

Zig verifies returned values carefully.

Incorrect example:

```zig
fn test() i32 {
    return "hello";
}
```

Compiler error:

```text
expected i32, found string
```

The compiler prevents invalid return types before execution.

## A Complete Example

```zig
const std = @import("std");

fn calculateArea(width: f64, height: f64) f64 {
    return width * height;
}

fn describe(area: f64) []const u8 {
    if (area > 100.0) {
        return "large";
    }

    return "small";
}

pub fn main() void {
    const area = calculateArea(12.0, 9.0);

    const text = describe(area);

    std.debug.print(
        "Area: {}, Type: {s}\n",
        .{ area, text },
    );
}
```

Output:

```text
Area: 108, Type: large
```

This program demonstrates several important ideas:

- returning numbers
- returning strings
- returning from branches
- passing returned values into other functions

Functions become much more powerful once they can produce results.

## Mental Model

You can think of a function as a transformation.

Input enters:

```text
parameters
```

processing happens:

```text
computation
```

output leaves:

```text
return value
```

This pattern appears everywhere in programming.

A large software system is often just thousands of small transformations connected together.

