This week I learned 20
This week I found a visual Brainfuck interpreter.
This week I noticed a difference in ownership semantics between Java and Rust.
In the Block syntax and semantics section of Crafting Interpreters, Bob implements block execution with some help from Java’s GC.
void executeBlock(List<Stmt> statements, Environment environment) {
Environment previous = this.environment;
try {
this.environment = environment;
for (Stmt statement : statements) {
execute(statement);
}
} finally {
this.environment = previous;
}
}
previous
is an alias to the current object’s environment. A few lines later,
the current object’s environment is reassigned to the method parameter
environment
. Java’s GC doesn’t chomp up the old environment since
previous
is still holding a reference to it. This means restoring the current
object’s environment
to previous
is safe.
The story is different in Rust. The programmer must be explicit. I decided to lean on Rust’s Rc type to emulate Java’s GC in rlox.
fn execute_block(&mut self, statements: Vec<Stmt>, environment: Environment) -> Result<()> {
// Things get a bit weird here. jlox leans on Java's GC to do this. We
// need to explicitly reference count our original `environment` so it
// doesn't get dropped when we *move* it.
let previous = Rc::clone(&self.environment);
self.environment = Rc::new(environment);
for statement in statements {
self.execute(statement)?;
}
self.environment = previous;
Ok(())
}
previous
is assigned to a reference counted instance of the current struct’s
environment
. This is imperative since the next line drops the old
environment (decreasing the reference count by 1).
This behavior is implicit in Java. Maybe that’s good. I tend to favor the brevity of Rust, though.