munificent / craftinginterpreters

Repository for the book "Crafting Interpreters"

Home Page:http://www.craftinginterpreters.com/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Challenge 11.4 unclear advantage of implementation

okomarov opened this issue · comments

The challenge reads:

Our resolver calculates which environment the variable is found in, but it’s still looked up by name in that map. A more efficient environment representation would store local variables in an array and look them up by index.

Extend the resolver to associate a unique index for each local variable declared in a scope. When resolving a variable access, look up both the scope the variable is in and its index and store that. In the interpreter, use that to quickly access a variable by its index instead of using a map.

The changes in the interpreter are:

 public class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
-  final Environment globals = new Environment();
+  final Map<String, Object> globals = new HashMap<>();
-  private Environment environment = globals;
+  private Environment environment;
   private final Map<Expr, Integer> locals = new HashMap<>();
+  private final Map<Expr, Integer> slots = new HashMap<>();

So all scoped environments become an array except globals. However, every time we need to lookup, define or get a variable, we need to get its location from slots. This feels like we swapped a map access from the environment to the locations.

Question

Am I correct in thinking that while we still have the same number of HashMap accesses, the advantage is that the variables are now stored in a contiguous block of memory since the Environment is now an array, and that the efficiency is coming from this change in memory layout rather than not having any HashMap access at all?

In other words, accessing slots is faster than accessing values (old Environment.java code):

private final Map<Expr, Integer> slots = new HashMap<>();

vs

private final Map<String, Object> values = new HashMap<>();