Non-local variable
In computer programming, a variable which is not defined in the local scope
- 3 min read
- 2 chapters
Related on Lably
Through Scope (computer programming), Local variable and Recursion (computer science)
In Lua they are called the upvalues of the function.
Examples
Nested functions
In the Python 3 example that follows there is a nested function inner defined in the scope of another function outer. The variable x is local to outer, but non-local to inner (nor is it global):
<span id="mwHw"></span><span class="kn" id="mwIA">from</span><span class="w" id="mwIQ"> </span><span class="nn" id="mwIg">typing</span><span class="w" id="mwIw"> </span><span class="kn" id="mwJA">import</span> <span class="n" id="mwJQ">Callable</span> <span class="k" id="mwJg">def</span><span class="w" id="mwJw"> </span><span class="nf" id="mwKA">outer</span><span class="p" id="mwKQ">()</span> <span class="o" id="mwKg">-></span> <span class="n" id="mwKw">Callable</span><span class="p" id="mwLA">[[],</span> <span class="kc" id="mwLQ">None</span><span class="p" id="mwLg">]:</span> <span class="n" id="mwLw">x</span><span class="p" id="mwMA">:</span> <span class="nb" id="mwMQ">int</span> <span class="o" id="mwMg">=</span> <span class="mi" id="mwMw">1</span> <span class="k" id="mwNA">def</span><span class="w" id="mwNQ"> </span><span class="nf" id="mwNg">inner</span><span class="p" id="mwNw">()</span> <span class="o" id="mwOA">-></span> <span class="kc" id="mwOQ">None</span><span class="p" id="mwOg">:</span> <span class="k" id="mwOw">nonlocal</span> <span class="n" id="mwPA">x</span> <span class="n" id="mwPQ">x</span> <span class="o" id="mwPg">+=</span> <span class="mi" id="mwPw">1</span> <span class="nb" id="mwQA">print</span><span class="p" id="mwQQ">(</span><span class="n" id="mwQg">x</span><span class="p" id="mwQw">)</span> <span class="k" id="mwRA">return</span> <span class="n" id="mwRQ">inner</span>
In JavaScript, the locality of a variable is determined by the closest var statement for this variable. In the following example, x is local to outer as it contains a var x statement, while inner doesn't. Therefore, x is non-local to inner:
<span id="mwTw"></span><span class="kd" id="mwUA">function</span><span class="w" id="mwUQ"> </span><span class="nx" id="mwUg">outer</span><span class="p" id="mwUw">()</span><span class="w" id="mwVA"> </span><span class="p" id="mwVQ">{</span> <span class="w" id="mwVg"> </span><span class="kd" id="mwVw">var</span><span class="w" id="mwWA"> </span><span class="nx" id="mwWQ">x</span><span class="w" id="mwWg"> </span><span class="o" id="mwWw">=</span><span class="w" id="mwXA"> </span><span class="mf" id="mwXQ">1</span><span class="p" id="mwXg">;</span> <span class="w" id="mwXw"> </span><span class="kd" id="mwYA">function</span><span class="w" id="mwYQ"> </span><span class="nx" id="mwYg">inner</span><span class="p" id="mwYw">()</span><span class="w" id="mwZA"> </span><span class="p" id="mwZQ">{</span> <span class="w" id="mwZg"> </span><span class="nx" id="mwZw">x</span><span class="w" id="mwaA"> </span><span class="o" id="mwaQ">+=</span><span class="w" id="mwag"> </span><span class="mf" id="mwaw">1</span><span class="p" id="mwbA">;</span> <span class="w" id="mwbQ"> </span><span class="nx" id="mwbg">console</span><span class="p" id="mwbw">.</span><span class="nx" id="mwcA">log</span><span class="p" id="mwcQ">(</span><span class="nx" id="mwcg">x</span><span class="p" id="mwcw">);</span> <span class="w" id="mwdA"> </span><span class="p" id="mwdQ">}</span> <span class="w" id="mwdg"> </span><span class="k" id="mwdw">return</span><span class="w" id="mweA"> </span><span class="nx" id="mweQ">inner</span><span class="p" id="mweg">;</span> <span class="p" id="mwew">}</span>Anonymous functions
In the Haskell example that follows the variable c is non-local in the anonymous function \x -> x + c:
<span id="mwgg"></span><span class="nf" id="mwgw">outer</span><span class="w" id="mwhA"> </span><span class="ow" id="mwhQ">=</span><span class="w" id="mwhg"> </span><span class="kr" id="mwhw">let</span><span class="w" id="mwiA"> </span><span class="n" id="mwiQ">c</span><span class="w" id="mwig"> </span><span class="ow" id="mwiw">=</span><span class="w" id="mwjA"> </span><span class="mi" id="mwjQ">1</span><span class="w" id="mwjg"> </span><span class="kr" id="mwjw">in</span><span class="w" id="mwkA"> </span><span class="n" id="mwkQ">map</span><span class="w" id="mwkg"> </span><span class="p" id="mwkw">(</span><span class="nf" id="mwlA">\</span><span class="n" id="mwlQ">x</span><span class="w" id="mwlg"> </span><span class="ow" id="mwlw">-></span><span class="w" id="mwmA"> </span><span class="n" id="mwmQ">x</span><span class="w" id="mwmg"> </span><span class="o" id="mwmw">+</span><span class="w" id="mwnA"> </span><span class="n" id="mwnQ">c</span><span class="p" id="mwng">)</span><span class="w" id="mwnw"> </span><span class="p" id="mwoA">[</span><span class="mi" id="mwoQ">1</span><span class="p" id="mwog">,</span><span class="w" id="mwow"> </span><span class="mi" id="mwpA">2</span><span class="p" id="mwpQ">,</span><span class="w" id="mwpg"> </span><span class="mi" id="mwpw">3</span><span class="p" id="mwqA">,</span><span class="w" id="mwqQ"> </span><span class="mi" id="mwqg">4</span><span class="p" id="mwqw">,</span><span class="w" id="mwrA"> </span><span class="mi" id="mwrQ">5</span><span class="p" id="mwrg">]</span>
Sign in to keep reading
One more chapter is free with a Lably account.
Implementation issues
Non-local variables are the primary reason it is difficult to support nested, anonymous, higher-order and thereby first-class functions in a programming language.
If the nested function or functions are (mutually) recursive, it becomes hard for the compiler to know exactly where on the call stack the non-local variable was allocated, as the frame pointer only points to the local variable of the nested function itself and there can be an arbitrary number of activation records on the stack in between. This is generally solved using access links or display registers.
If the nested function is passed as an argument to a higher-order function a closure needs to be built in order to locate the non-local variables. If the nested function is returned as a result from its outer function (or stored in a variable) the non-local variables will no longer be available on the stack. They need to be heap allocated instead, and their lifetime extends beyond the lifetime of the outer function that declared and allocated them. This generally requires garbage-collection.

