Skip to content

Commit

Permalink
chore: Update mutability docs (#4298)
Browse files Browse the repository at this point in the history
# Description

## Problem\*

Resolves <!-- Link to GitHub Issue -->

## Summary\*

While working on #4293 I noticed our mutability docs were quite
outdated, so I updated them.

## Additional Context



## Documentation\*

Check one:
- [ ] No documentation needed.
- [x] Documentation included in this PR.
- [ ] **[Exceptional Case]** Documentation to be submitted in a separate
PR.

# PR Checklist\*

- [x] I have tested the changes locally.
- [x] I have formatted the changes with [Prettier](https://prettier.io/)
and/or `cargo fmt` on default settings.
  • Loading branch information
jfecher authored Feb 7, 2024
1 parent fae4ead commit f14ecd8
Showing 1 changed file with 55 additions and 27 deletions.
82 changes: 55 additions & 27 deletions docs/docs/noir/concepts/mutability.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
---
title: Mutability
description:
Learn about mutable variables, constants, and globals in Noir programming language. Discover how
Learn about mutable variables in Noir. Discover how
to declare, modify, and use them in your programs.
keywords: [noir programming language, mutability in noir, mutable variables, constants, globals]
keywords: [noir programming language, mutability in noir, mutable variables]
sidebar_position: 8
---

Expand Down Expand Up @@ -49,45 +49,73 @@ fn helper(mut x: i32) {
}
```

## Comptime Values
## Non-local mutability

:::warning
Non-local mutability can be achieved through the mutable reference type `&mut T`:

The 'comptime' keyword was removed in version 0.10. The comptime keyword and syntax are currently still kept and parsed for backwards compatibility, but are now deprecated and will issue a warning when used. `comptime` has been removed because it is no longer needed for accessing arrays.

:::
```rust
fn set_to_zero(x: &mut Field) {
*x = 0;
}

## Globals
fn main() {
let mut y = 42;
set_to_zero(&mut y);
assert(*y == 0);
}
```

Noir also supports global variables. However, they must be known at compile-time. The global type can also be inferred by the compiler entirely. Globals can also be used to specify array
annotations for function parameters and can be imported from submodules.
When creating a mutable reference, the original variable being referred to (`y` in this
example) must also be mutable. Since mutable references are a reference type, they must
be explicitly dereferenced via `*` to retrieve the underlying value. Note that this yields
a copy of the value, so mutating this copy will not change the original value behind the
reference:

```rust
global N: Field = 5; // Same as `global N: Field = 5`
fn main() {
let mut x = 1;
let x_ref = &mut x;

let mut y = *x_ref;
let y_ref = &mut y;

fn main(x : Field, y : [Field; N]) {
let res = x * N;
x = 2;
*x_ref = 3;

assert(res == y[0]);
y = 4;
*y_ref = 5;

let res2 = x * my_submodule::N;
assert(res != res2);
assert(x == 3);
assert(*x_ref == 3);
assert(y == 5);
assert(*y_ref == 5);
}
```

mod my_submodule {
use dep::std;
Note that types in Noir are actually deeply immutable so the copy that occurs when
dereferencing is only a conceptual copy - no additional constraints will occur.

global N: Field = 10;
Mutable references can also be stored within structs. Note that there is also
no lifetime parameter on these unlike rust. This is because the allocated memory
always lasts the entire program - as if it were an array of one element.

fn my_helper() -> Field {
let x = N;
x
```rust
struct Foo {
x: &mut Field
}

impl Foo {
fn incr(mut self) {
*self.x += 1;
}
}
```

## Why only local mutability?
fn main() {
let foo = Foo { x: &mut 0 };
foo.incr();
assert(*foo.x == 1);
}
```

Witnesses in a proving system are immutable in nature. Noir aims to _closely_ mirror this setting
without applying additional overhead to the user. Modeling a mutable reference is not as
straightforward as on conventional architectures and would incur some possibly unexpected overhead.
In general, you should avoid non-local & shared mutability unless it is needed. Sticking
to only local mutability will improve readability and potentially improve compiler optimizations as well.

0 comments on commit f14ecd8

Please sign in to comment.