3

The following Python program A outputs 1, as expected, while the following Python program B raises an unbound local variable x error, counterintuitively.

  • Program A:
def f(): print(x)
x = 1
f()
  • Program B:
def f(): print(x); x = 2
x = 1
f()

Javascript has the exact same behaviour.

  • Program A:
function f() { console.log(x); }
let x = 1;
f();
  • Program B:
function f() { console.log(x); let x = 2; }
let x = 1;
f();

However, C++ outputs 1 in both cases, as expected.

  • Program A:
#include <iostream>
int x;
void f() { std::cout << x; }
int main() { x = 1; f(); return 0; }
  • Program B:
#include <iostream>
int x;
void f() { std::cout << x; int x = 2; }
int main() { x = 1; f(); return 0; }

So all programs A output 1. The differences in programs B between Python and Javascript on the one hand, and C++ on the other hand, result from their different scoping rules: in C++, the scope of a variable starts at its declaration, while in Python and Javascript, it starts at the beginning of the block where the variable is declared. Consequently, in C++ printing variable x in function f resolves to the value 1 of global variable x since it is the only variable in context at this point of execution. In Python and Javascript printing variable x in function f resolves to nothing and raises an unbound local variable x error since local variable x is already in context at this point of execution and therefore it masks global variable x without being bound yet to the value 2. This counterintuitive behaviour of Python and Javascript is also known as variable hoisting since it ‘hoists’ variable declarations (but not definitions) at the beginning of their blocks.

What are the benefits and drawbacks of variable hoisting in programming languages?

Géry Ogam
  • 6,336
  • 4
  • 38
  • 67
  • "_counterintuitive behaviour_" is due to the block/function scope. Under the hood, declarations are faster to find from the top of their scope, when resolving variables in nested scopes. Originally in JS (interpreted, `var` and function scope only), you could run "stupid" code without breaking the execution. The drawback was hard debuggable logic errors. – Teemu Aug 10 '20 at 09:56
  • @Teemu Yes `var` does not break execution like `let` does since it assigns the value `undefined` to local variable `x` instead of nothing, but the scope of local variable `x` remains the same since it still masks global variable `x` like `let` does. – Géry Ogam Aug 10 '20 at 11:06
  • Yep, that's a consequence of hoisting. In the context of `let` (and `const`), a term [`temporal dead-zone`](https://stackoverflow.com/questions/47634568/javascript-temporal-dead-zone) is used. – Teemu Aug 10 '20 at 11:30
  • 1
    Guido van Rossum (creator of Python) himself answered [here](https://discuss.python.org/t/why-does-python-have-variable-hoisting-like-javascript/4944). – Géry Ogam Aug 29 '20 at 15:08

1 Answers1

1

This is more a artifact of the language, rather than a programmer oriented feature.

For python and javascript, the new variable means allocate an entry in the name dictionary, until you actually create an object and assign it. In C++ there is no name dictionary in the run-time, the definition needs to actually allocate memory for the object (and it could be a 10MB array for all we know).

This does allow C++ to fit into smaller memory footprint if you really need that. Otherwise there's no much reason to think about it.

From the developer's perspective you have a bug. Your x has 2 meanings. Programming is hard enough as it is without having variables change meaning on you, so I would avoid as much as possible. I think C++ would give you a warning in some such a cases.

In practice you would get used to either setup.

Sorin
  • 11,863
  • 22
  • 26
  • Interesting. So are you saying that variable hoisting is a desirable programming feature because it prevents name binding to both a non local entity and a local entity in the same block? No, neither Clang nor GCC give a warning for the C++ programs. – Géry Ogam Aug 10 '20 at 12:08
  • https://stackoverflow.com/questions/25151524/get-warning-when-a-variable-is-shadowed – Sorin Aug 10 '20 at 12:13
  • @Maggyero I would prefer a clear Warning or Error to tell you this is happening. The errors you get in your hoisting examples can be misinterpreted and worked around. – Sorin Aug 10 '20 at 12:16
  • 1
    I asked the question about the motivation for variable hoisting on the official Python forum and finally Guido himself gave the rationale. If you are interested, the post is [here](https://discuss.python.org/t/why-does-python-have-variable-hoisting-like-javascript/4944). – Géry Ogam Aug 18 '20 at 15:44