|
| 1 | +# Traits |
| 2 | + |
| 3 | +Verus supports writing specifications for trait functions, including `requires` and |
| 4 | +`ensures` clauses. Specifications on a trait function serve as a *contract* that all |
| 5 | +implementations must satisfy, and that callers can rely on when they call the function |
| 6 | +through a trait bound. |
| 7 | + |
| 8 | +For traits defined in external crates (e.g., from the Rust standard library), see |
| 9 | +[External trait specifications](./external_trait_specifications.md). |
| 10 | + |
| 11 | +## Trait function specifications |
| 12 | + |
| 13 | +Trait functions can have `requires` and `ensures` clauses just like ordinary functions: |
| 14 | + |
| 15 | +```rust |
| 16 | +{{#include ../../../../examples/guide/traits.rs:basic_trait}} |
| 17 | +``` |
| 18 | + |
| 19 | +Any type implementing `Compressor` must provide a `compress` function whose body |
| 20 | +satisfies `output <= input`. |
| 21 | + |
| 22 | +## Extending specifications in implementations |
| 23 | + |
| 24 | +An implementation automatically inherits all `requires` and `ensures` clauses from the |
| 25 | +trait declaration. Additionally: |
| 26 | + |
| 27 | + * An `impl` **can** add stronger `ensures` clauses. |
| 28 | + * An `impl` **cannot** add new `requires` clauses — that would be unsound, because a |
| 29 | + caller using the trait bound `C: Compressor` has no obligation to satisfy |
| 30 | + requirements that the trait doesn't mention. |
| 31 | + |
| 32 | +```rust |
| 33 | +{{#include ../../../../examples/guide/traits.rs:impl_extends}} |
| 34 | +``` |
| 35 | + |
| 36 | +`HalfCompressor::compress` inherits `ensures output <= input` from the trait. |
| 37 | +Verus verifies that the function's body satisfies both the inherited postcondition |
| 38 | +and the additional postcondition added by the implementation (`ensures output == input / 2`). |
| 39 | + |
| 40 | +A trait function can also include both `requires` and `ensures`: |
| 41 | + |
| 42 | +```rust |
| 43 | +{{#include ../../../../examples/guide/traits.rs:requires_ensures}} |
| 44 | +``` |
| 45 | + |
| 46 | +```rust |
| 47 | +{{#include ../../../../examples/guide/traits.rs:requires_ensures_impl}} |
| 48 | +``` |
| 49 | + |
| 50 | +## Generic vs. concrete dispatch |
| 51 | + |
| 52 | +When Verus can statically determine the concrete type of a trait function call, it uses |
| 53 | +the possibly-stronger specification from the `impl`. When the call is through a generic |
| 54 | +type parameter, Verus only knows the trait-level specification. |
| 55 | + |
| 56 | +```rust |
| 57 | +{{#include ../../../../examples/guide/traits.rs:dispatch}} |
| 58 | +``` |
| 59 | + |
| 60 | +## Spec and proof functions |
| 61 | + |
| 62 | +A trait may also contain `spec` and `proof` function declarations. |
| 63 | +For example, the trait below requires implementations to provide |
| 64 | +a distance metric (`dist`) as a specification function and then to prove that |
| 65 | +their `distance` function actually computes that metric. |
| 66 | +Moreover, the implementation must also prove (in its body for `valid_distance_metric`) |
| 67 | +that `dist` is a reasonable metric. |
| 68 | + |
| 69 | +```rust |
| 70 | +{{#include ../../../../examples/guide/traits.rs:spec_trait}} |
| 71 | +``` |
| 72 | + |
| 73 | +Here's an example of an implementation of our `Distance` trait: |
| 74 | +```rust |
| 75 | +{{#include ../../../../examples/guide/traits.rs:spec_trait_impl}} |
| 76 | +``` |
| 77 | +In this case, Verus can automatically prove all of the postconditions |
| 78 | +for `valid_distance_metric`, but a more complex distance metric might |
| 79 | +need additional proof annotations. |
| 80 | + |
| 81 | +Note that it's not necessary to repeat the requires/ensures that |
| 82 | +the implementation inherits from the trait definition. |
| 83 | + |
| 84 | + |
| 85 | +## The `View` trait |
| 86 | + |
| 87 | +The most commonly used trait in `vstd` is `View`. It allows users to give |
| 88 | +executable types a mathematical abstraction (`type V`) accessed via the `view` |
| 89 | +function. Since this is such a commonly invoked function, Verus provides the |
| 90 | +[`@` operator](reference-at-sign.md) as a shortcut, so that you can write `x@` |
| 91 | +instead of `x.view()`. |
| 92 | + |
| 93 | +```rust |
| 94 | +pub trait View { |
| 95 | + type V; |
| 96 | + spec fn view(&self) -> Self::V; |
| 97 | +} |
| 98 | +``` |
| 99 | + |
| 100 | +`vstd` provides `View` implementations for common types: |
| 101 | +- `Vec<T>` → `Seq<T>` |
| 102 | +- `HashMap<K, V>` → `Map<K, V>` |
| 103 | +- `HashSet<K>` → `Set<K>` |
| 104 | +- Primitive types (`u64`, `bool`, etc.) → themselves |
| 105 | + |
| 106 | +To implement `View` for a custom type, choose an appropriate abstraction and |
| 107 | +then define `type V` and `spec fn view`: |
| 108 | + |
| 109 | +```rust |
| 110 | +{{#include ../../../../examples/guide/traits.rs:view_impl}} |
| 111 | +``` |
| 112 | + |
| 113 | +Because `Stack`'s `data` is a private field, `view` is `closed` — callers cannot see its |
| 114 | +definition, but they can still reason about the effect each function has on that view, |
| 115 | +as illustrated by the postconditions on `push` and `is_empty`. If you want |
| 116 | +callers to unfold `@` to its definition (e.g., for a `pub` type with a `pub` |
| 117 | +field), use `open spec fn view` instead. |
| 118 | + |
| 119 | +`vstd` also provides `DeepView`, which recursively applies the view abstraction |
| 120 | +to nested elements. Most code only needs `View`. |
| 121 | + |
| 122 | +## `default_ensures`: specifications for default function implementations |
| 123 | + |
| 124 | +In Rust, a trait function can provide a *default implementation* — a body that |
| 125 | +implementations inherit if they do not override the function. This creates a subtle |
| 126 | +specification problem: the trait-level `ensures` clause must be weak enough to allow |
| 127 | +any valid override, but the default body may satisfy a *stronger* postcondition. |
| 128 | + |
| 129 | +`default_ensures` solves this by separating these two concerns: |
| 130 | + |
| 131 | +```rust |
| 132 | +{{#include ../../../../examples/guide/traits.rs:default_ensures}} |
| 133 | +``` |
| 134 | + |
| 135 | +Here the **trait-level `ensures`** (`output <= input`) is what any implementation must |
| 136 | +satisfy. The **`default_ensures`** (`output == input / 2`) is an additional guarantee |
| 137 | +that holds *only* when a type uses the default implementation without overriding it. |
| 138 | + |
| 139 | +The rules: |
| 140 | + |
| 141 | + * `default_ensures` is only allowed on a trait function that has a default body in the |
| 142 | + trait declaration. |
| 143 | + * `default_ensures` is checked against the default body just like a normal `ensures`. |
| 144 | + * Callers that statically know the type inherits the default learn both `ensures` and |
| 145 | + `default_ensures`; callers using a generic bound `T: Trait` learn only the `ensures`. |
| 146 | + |
| 147 | +```rust |
| 148 | +{{#include ../../../../examples/guide/traits.rs:default_ensures_impls}} |
| 149 | +``` |
| 150 | + |
| 151 | +```rust |
| 152 | +{{#include ../../../../examples/guide/traits.rs:default_ensures_callers}} |
| 153 | +``` |
| 154 | + |
| 155 | +When writing your own trait, consider using `default_ensures` on functions |
| 156 | +where a sensible default makes a stronger promise that custom implementations |
| 157 | +are not required to match. |
| 158 | + |
| 159 | +## Common `vstd` trait specifications |
| 160 | + |
| 161 | +`vstd` provides specifications for many standard library traits. A few worth knowing: |
| 162 | + |
| 163 | + * **`PartialEq` / `Eq`** — `vstd` wraps these with an `obeys_eq_spec()` guard so that |
| 164 | + only types that opt in are assumed to satisfy the functional equality contract. |
| 165 | + See [External trait specifications](./external_trait_specifications.md) for the |
| 166 | + `obeys_*` pattern. |
| 167 | + * **`Iterator`** — `vstd` provides `IteratorSpecImpl` (not `Iterator` directly) for |
| 168 | + writing specs on custom iterators. See [Iterator Specifications](./iterator-specs.md). |
| 169 | + * **`PartialOrd` / `Ord`** — similar to `PartialEq`, with `obeys_ord_spec()` guards. |
| 170 | + |
| 171 | +## External trait specifications |
| 172 | + |
| 173 | +For adding specifications to traits from external crates (including `std`), see |
| 174 | +[External trait specifications](./external_trait_specifications.md). |
0 commit comments