---
title: "2.5 Why functions are useful"
description: "The five things functions buy you, when to split code into one, and the read-compute-print pattern."
url: "https://learnrust.net/chapter-2/why-functions-are-useful/"
last_updated: "2026-06-11"
---

# 2.5 Why functions are useful

Now that you can write functions, an honest question deserves an honest answer: why bother? Everything so far *could* have been one long `main`. For a ten-line program, it even should be. But programs grow, and somewhere around the point where one screen can't hold `main`, functions change from ceremony into survival gear. Here's precisely what they buy.

**Organization.** A 5,000-line `main` is a junk drawer; nobody finds anything, and every change risks disturbing strangers. The same code as a hundred fifty-line functions is a labeled toolbox. Each function has a name, a job, and a boundary, and the boundary is real: as lesson [2.4](https://learnrust.net/chapter-2/local-scope-and-blocks/) showed, what happens in a function stays in a function, except what's deliberately passed through the doors.

**Reuse.** Code in a function runs anywhere, any number of times, by name. That's the DRY principle from lesson [2.2](https://learnrust.net/chapter-2/return-values/) made practical, and it's bigger than saving keystrokes: when duplicated logic needs a fix, every copy is a chance to forget one. Code that exists once gets fixed once.

**Testing.** A function with defined inputs and outputs can be checked by itself: call it with known arguments, compare against known answers. You can do that by hand today (a few temporary calls in `main`), and chapter 14 will show you Rust's built-in machinery that does it automatically, forever, on every build. That machinery needs the seams functions create; you can't unit-test a paragraph in the middle of a 500-line `main`.

**Extensibility.** When behavior lives in one function, upgrading the behavior is editing one place, and every caller benefits without knowing anything changed.

**Abstraction.** The quiet superpower. To *use* a function, you need its name, inputs, and output. You don't need to know how it works inside. You've been living this all course: you have no idea how `println!` arranges for characters to appear on your screen, and it has cost you nothing. Every function you write extends that same courtesy to its callers, including future-you, who will gratefully read `let total = score_for_round(rolls);` without re-deriving the scoring rules.

## When to reach for one

Useful rules of thumb, tuned for where you are now:

Code that appears more than once wants to be a function (that's DRY again, and it's the most mechanical trigger). A chunk with one clear job and an obvious input/output shape wants to be a function even if it appears once, because the name documents the job. And when a function has grown past "fits comfortably on a screen" or needs the word "and" twice to describe, it wants to become two.

The most common shape for small interactive programs gives you the pattern for free: something like *read the inputs, compute the result, print the result*. That's three jobs; lesson [2.6](https://learnrust.net/chapter-2/designing-your-first-programs/) makes a method of it.

One anti-pattern to dodge from day one: the function that computes a result and *also* prints it. Two jobs in one body means no caller can ever get the value without the printing (or the printing without the value), and the chapter 14 test machinery can't check it cleanly. Compute *or* print; let `main` introduce them to each other.

> **Best practice**
>
> One function, one job, named for the job. If naming it requires "and," it's two functions wearing a coat.

## Quiz time

**Question #1**

This function bundles two jobs. What are they, and what should the split look like?

```rust
fn report_area(width: i32, height: i32) {
    let area = width * height;
    println!("The area is {area}");
}
```

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

It computes the area *and* prints it. Split: `fn area(width: i32, height: i32) -> i32 { width * height }`, and let the caller decide what to do with the value (print it, compare it, store it). The compute half is now reusable and testable; printing stays a one-liner in `main`.

</details>

**Question #2**

Your program asks for three numbers using three copies of the read-and-parse recipe. What's the refactor, and which benefit from this lesson is doing the work?

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

Extract one `get_number() -> i32` function and call it three times (exactly as lesson 2.2 did). Primarily reuse/DRY, with testing and extensibility riding along: when input handling improves in chapter 12, one function upgrades all three call sites.

</details>

Functions are worth using well, which raises the design question: given a problem, how do you decide what the functions *are*? That's the next lesson, and it's the chapter's payoff.

## Sitemap

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