A JavaScript default function parameter quirk for Python programmers


Default parameters are a great convenience in most modern programming languages. Default parameters fix the ‘default’ parameter to a function, in case the parameter is not available. For example, a function greet_hello(name='david') would give 'hello david, but greet(name='davidos', greeting='Hola' will give Hola davidos. But that’s just the definition. The implementations could differ, and that is exactly the point of this port. This article is about default parameters handled differently in Python and JavaScript.

Python

Let’s say you have function foo defined thus:

>>> def foo(str1=a, str2=b):
...     return str1+str2
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined

What happened? Well, the Python rules for function definition make sure that a and b are defined beforehand. In other words, the default parameters in Python are evaluated only once i.e. at the time of function declaration.

For instance, here’s a version that works as expected because a and b are already defined before foo is.

>>> a = "Hello"
>>> b = "World"
>>> def foo(a=a, b=b):
...     return a+b
...
>>> foo()
'HelloWorld

As a matter of fact, the default parameters have to be defined beforehand. Otherwise how could you even utilize __defaults__ of foo?

>>> foo.__defaults__
('Hello', 'World')

JavaScript

Python being my first-language, JavaScript’s function assignment rules seemed ‘very dynamic’ at first, to say the least. For instance, JavaScript will happily accept the version that Python didn’t.

>> function foo(str1=a, str2=b){
     return str1+str2;
   }
>> undefined

If you call foo() at this point, you’d get an error saying Uncaught ReferenceError: a is not defined. However, unlike Python, foo is, nonetheless, actually defined. At this or at any point later, if the JavaScript runtime environment can find a variable a and b defined in the runtime environment, it will make foo run without any errors!

As a matter of fact, the default variables can be totally dynamic! Let’s assume that the function foo is defined as above and then we run the following sequentially:

>> a = "Hello"
>> "Hello"
>> b = "World"
>> "World"
>> foo()
>> "HelloWorld"
>> // I will now redefine `a` and `b`
>> a = "Stop"
>> "Stop"
>> b = "War"
>> "War"
>> foo()
>> "StopWar"

Did you see that? foo’s default parameters will always be pulled from the runtime scope.

Honestly, I don’t see many pragmatic use cases right away for this aspect, but I found it really dynamic (pun intended). And it could easily become a quirk to screw oneself over for multilingual programmers.

Home Work

What happens if you try to change the function signature of foo to foo(a=a, b=b)? Why?