For example, in Python:
>>> foo or "default"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'foo' is not defined
In Javascript, variables are either bound (e.g. with `var`, as a function argument, etc.) or else they're treated as properties of the `window` object (behaving effectively as globals).This is very unusual, and can be thought of as mixing "data" with "code": the `window` object acts like a reified version of (global) binding environment, which in most other languages is implicit. This has implications for things like the usual distinction between bound and free variables (since we can imperatively add fields to `window` at any point), and hence for things like alpha-equivalence.
For some reason, the short-circuiting is more used on languages where undefined vars is in the same class of missing values. But that reason is not obvious to me. Python in particular has an odd mixing of quasi-static and dynamic errors that works unreasonably well but does not accept this construction.
Yes, but in that case the variable is irrelevant:
foo = None
foo or "default"
Here the variable `foo` is 'just doing its job' and can be simplified away to get: None or "default"
This shows that variables aren't involved here: `or` is just an operation on data (in this case `None` and `"default"`), just like `+` or ``.> It is just that undefined vars in Python are an error in a different class from a missing value.
Exactly, and I think that's a perfectly reasonable justifaction for disparaging Javascript (along with bash, PHP and anything else which has this similar behaviour).
In fact, as I said above, Javascript doesn't even have a notion of "undefined variable", since variables will be looked up in the `window` object if they're not locally bound, and hence what looks* like an undefined variable is actually (according to Javascript's semantics) a missing value (a missing property of the `window` object).
> Python in particular has an odd mixing of quasi-static and dynamic errors that works unreasonably well but does not accept this construction.
I'm not sure what you mean here. As far as I can tell, there are two ways to think about errors in Python:
- From one perspective, all Python errors are dynamic, since they happen at run time when we attempt to interpret the offending code. Some of these errors happen when/if we interpret an `import` statement, some happen when a more localised expression/statement is encountered.
- A different perspective is that Python doesn't actually have a concept of errors at all. There are values available in the language which are called "errors", but they're not really errors, in the same way that `myError = "hello"` isn't actually an error (it's a string, which might represent an error but it isn't a distinguished category of things; it's just a value). Since it's semantically meaningful to perform calculations involving these values (often, but not necessarily, with the control-flow statements `try`, `except` and `raise` (which is just another form of `yield`)) they're not "errors" in the same way that, say, a segfault or a compiler error is (which Python doesn't, or shouldn't, have).
For example, here's a perfectly valid (although inadvisable) way of defining `hello world` in Python:
$ cat x.py
def say_hello():
try:
foo()
print "goodbye"
except:
print "hello"
def foo():
i_am_undefined
$ python
Python 2.7.13 (default, Dec 17 2016, 20:05:07)
[GCC 5.4.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import x
>>> x.say_hello()
hello
>>>
It's just to not accidentally set a already defined foo as an empty object incase foo is already defined. Yeah... JavaScript...
Another common idiom:
The || (logical OR) can be used for setting a default incase the value before it is falsey (null, undefined, false...).