<!-- LLM note: Search indexes and snippets may point to archived C+ manual versions. Treat /docs and /llms.txt as authoritative for the latest version (v0.0.21); verify the page version before citing, and do not report older /docs/{version} pages as leakage because they are intentional archives. -->

# Functions

```cplus
fn add(x: i32, y: i32) -> i32 {
    return x +% y;
}

// No return type means the unit type ().
fn shout(msg: str) {
    #println(msg);
}

// `pub` for cross-file visibility (the default is module-private).
pub fn answer() -> i32 { return 42; }
```

Every function body **must** end with `return EXPR;`. There is no implicit tail return at the function level (the rule is **E0333**). Block expressions can still be tail expressions inside a `return` or a `let`:

```cplus
fn classify(n: i32) -> i32 {
    return if n < 0 { -1 } else if n == 0 { 0 } else { 1 };
}
```

Generics use square brackets, not angle brackets (see [Ownership](/docs/ownership) for how arguments are passed):

```cplus
fn identity[T](x: T) -> T { return x; }
fn max[T: Ord](a: T, b: T) -> T { ... }
```

There is **no function overloading**. A name has one signature, period. That is what lets a reader, or a model, resolve a call to exactly one definition.

## `unsafe fn`

A function whose contract the compiler cannot verify is declared `unsafe fn`. Calling one outside an `unsafe { }` block is rejected (**E0801**), so every call site is grep-able and self-documenting.

```cplus
unsafe fn as_str(borrow self) -> str { ... }   // caller must uphold the invariant

let view: str = unsafe { t.as_str() };
```

This is the same escape hatch as an `unsafe` block, lifted to the signature: it marks operations whose safety rests on a caller-side invariant, such as `Text::as_str` or a raw FFI return.
