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.