---
title: "16.2 Default method implementations"
description: "A trait can provide default method bodies that implementing types get for free, can override, and can build on by calling other trait methods."
url: "https://learnrust.net/chapter-16/default-method-implementations/"
last_updated: "2026-06-13"
---

# 16.2 Default method implementations

The `Summary` trait in the last lesson required every implementer to write `summarize` from scratch. Often, though, a trait can provide a *default* version of a method, sensible behavior that implementing types get automatically and only override when they want something different. Default methods are the first way traits actively reduce the code you write, and they're the seed of how Rust reuses behavior without inheritance.

## A method with a default body

Give a trait method a body, instead of ending it with a semicolon, and that body becomes the default:

```rust
trait Summary {
    fn summarize(&self) -> String {
        String::from("(no summary available)")
    }
}

struct Article {
    headline: String,
}

impl Summary for Article {}

fn main() {
    let article = Article {
        headline: String::from("Rust 2.0 Released"),
    };
    println!("{}", article.summarize());
}
```

```
(no summary available)
```

Look at `impl Summary for Article {}`: it's *empty*. `Article` implements `Summary` but provides no `summarize`, so it inherits the trait's default body. The default isn't much here (a placeholder string), but the mechanism is the point: a trait can ship behavior, and a type opts into it by simply declaring it implements the trait. This is exactly how deriving works under the hood, and why `#[derive(Default)]` (lesson [10.6](https://learnrust.net/chapter-10/associated-functions-and-constructors/)) could hand you a `default()` you never wrote.

## Overriding the default

A type that wants different behavior just provides its own `summarize`, which **overrides** the default for that type:

```rust
struct Tweet {
    username: String,
    content: String,
}

impl Summary for Tweet {
    fn summarize(&self) -> String {
        format!("@{}: {}", self.username, self.content)
    }
}
```

`Tweet` provides its own `summarize`, so it uses that instead of the default. `Article` (empty impl) keeps the default; `Tweet` (its own method) overrides it. Implementers choose per type: take the default where it's fine, override where it isn't. There's no ceremony for either choice, and no way to half-implement, you either supply the method or you get the default.

## Default methods can call other trait methods

The real power: a default method can call *other* methods of the same trait, including ones with no default that each type must supply. This lets a trait define a small required core and build richer behavior on top of it, once, for everyone.

```rust
trait Summary {
    fn summarize_author(&self) -> String;     // required: no default

    fn summarize(&self) -> String {            // default, built on the above
        format!("(read more from {}...)", self.summarize_author())
    }
}

struct Tweet {
    username: String,
}

impl Summary for Tweet {
    fn summarize_author(&self) -> String {
        format!("@{}", self.username)
    }
}

fn main() {
    let tweet = Tweet { username: String::from("rustlang") };
    println!("{}", tweet.summarize());
}
```

```
(read more from @rustlang...)
```

`Tweet` implements only `summarize_author`, the one required method. It gets `summarize` for free, and that default calls `summarize_author` to do its job. So each type supplies the small piece that genuinely differs (who the author is), and the trait provides the larger behavior built on it (the formatted "read more" line) for every implementer at once. Add a hundred types implementing `Summary`, and they all share that one `summarize` body while each defines its own `summarize_author`.

> **Key insight**
>
> The "required core plus default methods built on it" pattern is how Rust reuses behavior the way other languages use inheritance, but without a base class. The trait defines a minimal contract (the required methods) and layers shared functionality on top (the defaults). Implementers fill in the contract and inherit the layer. The standard library leans on this constantly: the `Iterator` trait (chapter 19) requires just one method, `next`, and provides dozens of others (`map`, `filter`, `sum`) as defaults built on it. Implement `next`, get the rest free.

> **Best practice**
>
> When designing a trait, push as much behavior as you can into default methods built on a small set of required ones. It minimizes what each implementer must write and keeps the shared logic in one place. The question to ask is "what's the smallest set of methods a type must provide for me to build everything else?" That minimal set becomes the required methods; the rest become defaults.

## Quiz time

**Question #1**

What does an empty `impl Summary for Article {}` mean when `Summary` has a default `summarize`?

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

It means `Article` implements `Summary` but provides none of its own methods, so it uses the trait's default `summarize` body. The empty impl is enough to declare "this type has this trait"; the default supplies the behavior.

</details>

**Question #2**

How does a type override a default method, and what happens to types that don't?

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

A type overrides a default by providing its own implementation of that method in its `impl` block. Types that don't provide their own keep the trait's default. The choice is per type and per method: supply your own to override, or omit it to inherit the default.

</details>

**Question #3**

Why is "a small set of required methods plus default methods built on them" a powerful trait design? Give the standard-library example.

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

Because each implementing type only has to write the small required core, and gets all the default behavior built on it for free, with the shared logic living in one place. The example is `Iterator` (chapter 19): a type implements just `next`, and inherits dozens of provided methods (`map`, `filter`, `sum`, etc.) that are all defined in terms of `next`.

</details>

Traits define behavior; now the payoff the last chapter promised. The next lesson uses traits as **bounds** on generics, the feature that lets a generic function require "`T` can be compared" and finally makes `largest` compile.

## Sitemap

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