---
title: "2.1 Introduction to functions"
description: "Defining and calling Rust functions, tracing the flow of control, and why definition order doesn't matter."
url: "https://learnrust.net/chapter-2/introduction-to-functions/"
last_updated: "2026-06-11"
---

# 2.1 Introduction to functions

> **Chapter introduction**
>
> Chapter 1 ended with a program whose `main` did everything. That stops scaling almost immediately, and this chapter is about the fix: **functions**, the unit from which all larger program structure is built. By the chapter's end you'll be designing programs as teams of small functions, which is how all real Rust is written.

Lesson [1.1](https://learnrust.net/chapter-1/statements-and-program-structure/) defined a function as a named bundle of statements. That was true and incomplete. The better definition: a function is a reusable piece of program, with a name, dedicated to one job, which other code can run *as a step of its own work*. `main` is one. The upgrade in this chapter is that you start writing the others.

## Defining and calling a function

A function definition looks exactly like `main`'s, because `main` was never special syntax:

```rust
fn print_warning() {
    println!("Careful! The floor is wet.");
}
```

`fn`, a snake_case name, parentheses (empty for now; next lessons fill them), and a brace-wrapped body. Definitions can sit before or after `main` in the file, at the same level (not inside another function's braces, conventionally).

To run it, you **call** it by name, with parentheses:

```rust
fn main() {
    println!("Entering the kitchen.");
    print_warning();
    println!("Walking carefully.");
}

fn print_warning() {
    println!("Careful! The floor is wet.");
}
```

```
Entering the kitchen.
Careful! The floor is wet.
Walking carefully.
```

Follow the control flow, because this trace is the whole lesson: execution starts at `main`, prints the first line, and hits the call. At that moment `main` *pauses*, execution jumps into `print_warning`, runs its body, and when that body ends, execution returns to `main`, picking up exactly where it left off. Like putting a bookmark in one book to glance at another, the program never loses its place.

A function can be called as many times as you like; that's the "reusable" earning its keep:

```rust
fn main() {
    print_warning();
    print_warning();
}

fn print_warning() {
    println!("Careful! The floor is wet.");
}
```

```
Careful! The floor is wet.
Careful! The floor is wet.
```

And functions call functions. Each call adds a bookmark, each completed body returns to the most recent one:

```rust
fn main() {
    println!("main: start");
    do_a();
    println!("main: end");
}

fn do_a() {
    println!("a: start");
    do_b();
    println!("a: end");
}

fn do_b() {
    println!("b: here");
}
```

```
main: start
a: start
b: here
a: end
main: end
```

If you can predict that output cold, you understand function calls. (The machinery that tracks all those bookmarks is called the call stack, and it stars in lesson [3.5](https://learnrust.net/chapter-3/using-a-debugger/) where you'll watch it live.)

> **Warning**
>
> A function is called with parentheses: `print_warning()`. Write the name *without* them and you haven't called anything; oddly enough, `print_warning;` compiles, does nothing at all, and earns only a warning (a "path statement with no effect"). If a function mysteriously never runs, count your parentheses before you question your sanity.

## Definition order doesn't matter

Notice that `main` happily called functions defined *below* it in the file. Rust reads the whole file before judging any of it, so functions can be defined in whatever order reads best. The convention you'll see everywhere (and that this course uses) puts `main` first, helpers after, so files read top-down from the big picture to the details.

If you've seen C or C++, you'll recognize what's absent: no forward declarations, no prototypes, no "declared before use" choreography. That entire apparatus has no Rust equivalent at all, one more of the C++ chores lesson [0.3](https://learnrust.net/chapter-0/introduction-to-rust/) promised you'd never meet.

> **For advanced readers**
>
> Rust *does* allow defining a function inside another function's body. It's legal, occasionally tidy for a helper used in exactly one place, and rare in practice; the nested function is just an ordinary function whose name is only visible inside the enclosing one. File it away; everything in this course uses top-level functions.

## Quiz time

**Question #1**

In the three-function trace example above, what would the output be if `main`'s body were the two statements `do_b();` then `do_a();`?

<details class="solution">
<summary>Show solution</summary>

```
b: here
a: start
b: here
a: end
```

`do_b` runs first (one line), then `do_a` runs and calls `do_b` again as its middle step. Each call is a fresh visit.

</details>

**Question #2**

What's the difference between defining a function and calling it?

<details class="solution">
<summary>Show solution</summary>

Defining (`fn name() { ... }`) creates the function and runs nothing. Calling (`name();`) runs its body, then returns to the caller. A definition with no calls is dormant code; a call requires a definition to exist somewhere in the file.

</details>

**Question #3**

This program compiles. What happens when it runs, and what does the compiler mutter about?

```rust
fn main() {
    greet;
}

fn greet() {
    println!("Hello!");
}
```

<details class="solution">
<summary>Show solution</summary>

It prints nothing. `greet;` names the function without calling it (no parentheses), a statement with no effect, and the compiler warns exactly that ("path statement with no effect"). The fix is `greet();`.

</details>

So far our functions only *do*; they can't hand anything back. Return values, next, are where functions start participating in computation.

## Sitemap

See the full [sitemap](https://learnrust.net/sitemap.md) for all pages.
