Use Rust compiler to avoid common mistakes
sunjay opened this issue · comments
Sunjay Varma commented
We should see if there is some way to get the compiler and type system to prevent us from forgetting things like closing a loop, freeing allocated memory, move back to the left after moving right, etc.
It's too easy to forget to do that right now and it's causing tons of bugs. See codegen/if_condition.rs
for a file full of these problems.
The giant documentation comment at the top of codegen isn't enough.
Possible Options
Closures
instructions.move_to(pos, || {
//...generate more instructions...
});
instructions.jumps(cond_pos, || {
//...generate more instructions...
});
Pros:
- nice syntax
- automatically ensures balance declaratively, no type system magic required
Cons:
- might run into lifetime issues if we have multiple of these in a row (needs to be tested)
- not totally flexible since we might actually want one of those instructions without the other (we could probably just leave in the current functions for that use case)
What's the equivalent of this?instructions.move_right_by(cond_cell); instructions.jump_forward_if_zero(); instructions.move_left_by(cond_cell);
Structs
This is probably the best option. It's reasonably flexible and doesn't suffer the downsides of the closure method.
// must_use prevents this from being ignored when returned by a function
#[must_use]
struct Movement {
right: usize,
}
impl Movement {
// This consumes self, so the borrow checker will complain if this is used more than once
fn left(self) {
//...
}
}
fn move_right_by(n: usize) -> Movement {
//...
Movement {right: n}
}
Pros:
- Completely flexible, easy enough to add to existing code
Cons:
- Lots of initial boilerplate to setup (individual structs for each operation) - not that bad