As a concrete example for my question, here's a snippet in Python (which should be readable to the broadest number of people and which has a JVM implementation anyway):
def memo(f):
cache = {}
def g(*args):
if args not in cache:
cache[args] = f(*args)
return cache[args]
return g
How do industrial-strength languages compile a definition like this, in order to realize static scope? What if we only have nested definition but no higher order function-value parameters or return values, à la Pascal (and hence no need for closures)? I'm guessing that calculating static links is out, since you can't access the stack frame of a method call. So what is commonly done? Do they build anonymous inner classes? Lambda lifting? Something else?
Sorry if this is a question that's been asked before; it seems like it must be, but I haven't found anything that's quite right.
I will be answering your question from the standpoint of Clojure, the only JVM language whose translation strategy I know intimately. For concreteness, I have translated your Python to the following Clojure (not idiomatic or thread-safe, but this is not important here):
Inner classes (mentioned in the question and the comments) are a convenience for programmers, and the compiler doesn't need them1. Each Clojure function definition (not function invocation!) corresponds to a single top-level class implementing clojure.lang.IFn (usually through some abstract helper class). In that class, each closed-over lexical variable is saved as a field; these are initialized in the constructor. So this function definition expands to something like:
1In fact, in the version of Java that Clojure targets, inner classes don't exist at the JVM level - they are a fiction that the java compiler translates into separate top-level classes with secret access mechanisms, much as Clojure translates nested functions to top-level classes. In more recent versions of Java, the VM itself does actually understand nested classes.
For completeness, the full disassembled bytecode for
memoand its inner function follows below.