Skip to content

Commit 0421dbb

Browse files
committed
improve terminology: predicate -> condition, plus minor example tweaks
1 parent cf33958 commit 0421dbb

1 file changed

Lines changed: 14 additions & 13 deletions

File tree

README.md

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ anodized = "0.1.0"
2525

2626
**2. Add contracts to your functions.**
2727

28-
Use the `#[contract]` attribute to attach `requires` (precondition), `ensures` (postcondition), and `maintains` (invariant) _clauses_. Each clause contains a standard Rust expression that evaluates to `bool`, called a _predicate_. In an `ensures` clause, the function's return value is available as `output`.
28+
Use the `#[contract]` attribute to attach `requires` (precondition), `ensures` (postcondition), and `maintains` (invariant) _clauses_. Each clause contains a standard Rust expression that evaluates to `bool`, called a _condition_. In an `ensures` clause, the function's return value is available as `output`.
2929

3030
```rust
3131
use anodized::contract;
@@ -75,24 +75,25 @@ Anodized aims to support a wide spectrum of correctness tools, enabling you to c
7575

7676
The `#[contract]` attribute provides a powerful and ergonomic way to define contracts.
7777

78-
### Contracts, Clauses, and Predicates
78+
### Contracts, Clauses, and Conditions
7979

8080
Contracts are built from three flavors of clauses:
8181

82-
- `requires: <predicate>`: Defines a **precondition**. This predicate must be true when the function is called.
82+
- `requires: <condition>`: Defines a **precondition**. This condition must be true when the function is called.
8383

84-
- `ensures: <predicate>`: Defines a **postcondition**. This predicate must be true when the function returns.
84+
- `ensures: <condition>`: Defines a **postcondition**. This condition must be true when the function returns.
8585

86-
- `maintains: <predicate>`: Defines an **invariant**. A convenience to add a predicate as both a pre- and a postcondition. It's most useful for expressing properties of `self` that a method must preserve.
86+
- `maintains: <condition>`: Defines an **invariant**. A convenience to add a condition as both a pre- and a postcondition. It's most useful for expressing properties of `self` that a method must preserve.
8787

88-
A predicate is a `bool`-valued Rust expression; as simple as that. This is a non-trivial design choice, so its benefits are explained in the section below: [Why Predicates Are Rust Expressions](#why-predicates-are-rust-expressions).
88+
A condition is a `bool`-valued Rust expression; as simple as that. This is a non-trivial design choice, so its benefits are explained in the section below: [Why Conditions Are Rust Expressions](#why-conditions-are-rust-expressions).
8989

9090
You can include zero, one, or many clauses of each flavor. In terms of meaning (semantics), multiple clauses of the same flavor are combined with a logical **AND** (`&&`).
9191

9292
```rust
9393
#[contract(
94+
// These two `requires` clauses are equivalent to one with `self.is_initialized && !self.is_locked`
9495
requires: self.is_initialized,
95-
requires: !self.is_locked, // equivalent to `self.is_initialized && !self.is_locked`
96+
requires: !self.is_locked,
9697
maintains: self.len() <= self.capacity(),
9798
)]
9899
fn push(&mut self, value: T) { /* ... */ }
@@ -121,7 +122,7 @@ If the name `output` collides with an existing identifier, you can rename it in
121122
fn increment(old_value: i32) -> i32 { old_value + 1 }
122123
```
123124

124-
**2. Per-Clause Override**: Use a closure-style syntax on a specific `ensures` clause. This has the highest precedence and only affects that single clause.
125+
**2. Per-Clause Override**: Use a closure-style syntax in a specific `ensures` clause. This has the highest precedence and only affects that single clause.
125126

126127
```rust
127128
#[contract(
@@ -136,7 +137,7 @@ fn create_data() -> Data { /* ... */ }
136137
**3. Multiple Overrides**: When used together, the per-clause override always takes precedence for its specific clause, while other clauses fall back to the global override.
137138

138139
```rust
139-
// A function where 'output' is an argument name, requiring a global override.
140+
// A function where 'output' is an argument name, requiring overrides.
140141
#[contract(
141142
// Globally rename the return value to `result`.
142143
returns: result,
@@ -148,13 +149,13 @@ fn create_data() -> Data { /* ... */ }
148149
fn calculate_even_result(output: i32) -> i32 { /* ... */ }
149150
```
150151

151-
### Why Predicates Are Rust Expressions
152+
### Why Conditions Are Rust Expressions
152153

153-
A core design principle of Anodized is that a predicate is written as a **standard Rust expression** that evaluates to `bool`. This is a deliberate choice that provides key benefits over using a custom language.
154+
A core design principle of Anodized is that a condition is written as a **standard Rust expression** that evaluates to `bool`. This is a deliberate choice that provides key benefits over using a custom language.
154155

155-
- **The Language You Already Know**: No need to learn yet another language to write the contract predicates. Write them in the one you already know: standard Rust. Call functions, macros (like `matches!`), or write `if` and `match` expressions, and so on. As long as it all evaluates to a `bool`, you're good to go.
156+
- **The Language You Already Know**: No need to learn yet another language to write the contract conditions. Write them in the one you already know: standard Rust. Call functions, macros (like `matches!`), or write `if` and `match` expressions, and so on. As long as it all evaluates to a `bool`, you're good to go.
156157

157-
- **An Integral Part of Your Code**: Contract predicates aren't special comments or strings; they are real Rust expressions, fully integrated with your code. The Rust compiler checks every predicate for syntax and type errors, just like any other part of your code. If you misspell a variable, compare incompatible types, or make any other mistake, you'll get a familiar compiler error pointing directly to the predicate that needs fixing.
158+
- **An Integral Part of Your Code**: Contract conditions aren't special comments or strings; they are real Rust expressions, fully integrated with your code. The Rust compiler checks every condition for syntax and type errors, just like any other part of your code. If you misspell a variable, compare incompatible types, or make any other mistake, you'll get a familiar compiler error pointing directly to the condition that needs fixing.
158159

159160
## License
160161

0 commit comments

Comments
 (0)