By default, a nested function automatically "captures" a non-static local variable of an outer function when the following requirements are met:
- ...
- The inner function (or a function nested inside it) must refer to the variable non-dynamically.
...
Non-static local variables of the outer function cannot be accessed dynamically unless they have been captured.
Source: Functions - Definition & Usage | AutoHotkey v2
As you see, f2 does not refer to f1 or b non-dynamically, therefore it does not capture them, and cannot access them dynamically.
What is probably not explained in the documentation yet is that all closures defined directly within a function share the
same "set of free variables".
f1 is a closure because it captures
b, and f2 is a closure because it captures
a. Closures within a function are often related, so the design prioritises this and manages them as a single group, allowing them to refer to each other without causing reference cycles. This also means that the free variables can be allocated exactly once as a group, and do not need to be individually reference-counted. The drawback is that closures which are captured by other closures cannot be individually deleted. Holding a reference to any closure also holds a reference to the set of free variables used by all closures of the same outer function.
In your top post, f2 is not deleted because it is referenced by
b, which is part of the set of free variables referenced by f2 itself.