Having messed around with several scripting languages and being a bit of a linguist, there seems to be a way to divide dynamically typed languages into two groups: languages that give variables a default value, and languages that treat accessing an up-to-now unused variable an error.

For instance, consider this code:

  • In Lua, it prints nil
  • In PHP (with a semicolon and $), it prints nothing
  • In Perl (with a semicolon and $), it prints nothing (but using say yields an error)


  • In Python it throws a NameError
  • In Ruby, it throws a NameError (looks like Ruby ripped off Python's name for it)
  • In Javascript, it throws a ReferenceError
  • In Lisp, some type of error occurs that takes me to a debugger (I'm just learning Lisp now so I don't know what to call it)

Additionally, these languages behave differently when indexing an hash map, a similar operation, and they again fall into two camps (and when I say 'nothing' I mean that language's representation of nothing):

  • Lua returns nothing
  • PHP returns nothing
  • Ruby returns nothing
  • Perl returns nothing
  • Lisp returns nothing
  • Javascript returns nothing


  • Python throws a KeyError

So I am wondering what the comparative advantages and disadvantages are for a language to make accessing an undefined variable an error or just return a default value, and also what decisions would lead a language designer to choose one path or the other.

  • 1
    Actually, in Ruby it does not raise a NameError because the variable is uninitialized, it raises a NameError because Ruby can't figure out whether it's a reference to a local variable or a call to a method with no arguments. Uninitialized local variables evaluate to nil in Ruby. If you resolve the aforementioned ambiguity by sticking something like if false then hi = 42 end in front, you'll see that it evaluates to nil. Mar 14, 2012 at 1:35

2 Answers 2


Well, one thing to keep in mind is that it's harder to debug a misspelled variable or similar error if you do not have an error. Especially if you have to declare variables somehow (like with a define or var), chances are that using an undeclared variable is an error, so signalling it as such is probably the right thing to do.

However, there are also times when having it be some undefined value also makes sense. For example, in JavaScript accessing an argument that wasn't passed in is not an error:

(function (foo) {
})()// alerts 'undefined'

This also makes sense--while a global variable is something the programmer has to define, an argument can be anything somebody else passes into the function. Now, these cases are not 100% analogous, but it's something to keep in mind.

As for hashes it's a different story. Depending on the language, there will be many times you're dealing with a hash that wasn't yours. I think it's completely reasonable to expect a hash only containing some of the keys you need to be passed in as an argument to a fucntion, say, so letting you access keys not in the hash makes sense. Again borrowing from JavaScript, this would let us write code like:

function (options) {
  var color = options.color || "white",
      font  = options.font  || "palatino"

Since there are places where it's completely reasonable to access a key that was not set, I think making it return some value is better than signalling an error. Since the programmer did not have to define the hash himself--unlike local variables--this is more akin to the arguments of a function than local variables.

Also note that some of those languages have mechanisms for handling missing keys in a hash some special way. You may want to also provide some mechanism to let the programmer specify how these are handled, so that if they don't like your default behavior they can change it.

So, in summary: I think using an undeclared variable should be an error while accessing an undeclared field in a hash should not.

  • I disagree with the latter part of your answer (surprisingly, I'm a happy Python programmer). Most of the time when I get a KeyError in Python, I used the wrong thing as key, used the wrong dictionary, missed something when filling the dictionary, or otherwise had a bug/typo/oversight. On the occasions one does want to get a default value, that can be made explicit - e.g. color = options.get('color', "white") or using a dictionary spinoff that does use a default rather than raising - in Python, collections.defaultdict.
    – user7043
    Mar 13, 2012 at 20:44
  • I suspect that's largely because Python programmers know how their language works and do not rely on the behavior of missing keys. All my KeyErrors in Python have indeed been errors, while in JavaScript I use objects (the equivalent of Python's dicts) with only some of their fields initialized all the time in my code (for stuff like options). Mar 13, 2012 at 20:48
  • Well, for stuff like options, Python has default parameters and keyword arguments - which are naturally preferred. As JavaScript isn't nearly as rich when it comes to parameters, the pattern of passing an incomplete object literal is more useful. Still, you could follow exactly the same pattern in Python with next-to-no extra work (just use get(key, default) rather than .key || default). And you still get an error when you don't want that.
    – user7043
    Mar 13, 2012 at 20:55
  • This also reminds me that in certain languages like Lisp and Python, unless a parameter is explicitly given a default value, if you call a function with the wrong number of arguments it will error, whereas with languages like Lua and Ruby it does not. I guess this makes sense when your languages (like Lisp and Python) has more powerful ways of passing arguments. So basically the main consideration is misspelling? Mar 14, 2012 at 1:13

If you are trying to decide what you should do in a language you are designing, I would suggest providing syntactical forms programmers can use to indicate various expectations. As a hypothetical example (borrowing concepts from a few languages):

  • let x = someValue;
    Create a new read-only identifier x, and expect that any code which can ever see the new identifier will never be able to see any identifier that previously existed. It should be acceptable for x to already exist as a name, even in the current scope, provided that anything which can see the new definition will always do so.

  • declare x: someType;
    Create a new variable called x, which must be written to before it can be used. The identifier must not be declared anywhere else in the same scope.

  • def x: someType;
    Create a new variable called x and assign to it the default value associated with someType. The identifier must not be declared anywhere else in the same scope.

  • def x: someType = initialValue;
    Create a new variable called x and assign to it the specified initial value. The identifier must not be declared anywhere else in the same scope.

  • x = someValue;
    Changes the value associated with a variable created using declare or def.

For languages which allow code to create and manipulate variables in outer execution contexts (the examples below assume such variables are loosely typed):

  • create x = someValue;
    Requires that no variable x exists in the outer scope, and creates a new one. Should trap if the variable already exists.

  • import x (default = someValue)
    Indicates that within the present scope, x should refer to an outer-scope identifier; if none exists, create one with the indicated default value.

  • import x Indicates that within the present scope, x should refer to an outer-scope identifier, which must already exist (trap if it doesn't).

  • variableName! Yields the value of a variable in an outer scope with the indicated name, without having to make that name "directly" accessible throughout the present scope; traps if no such outer-scope name exists.

  • variableName ?| defaultValue Yields the value of an outer-scope variable if it exists, or the indicated default value if not. Neither creates nor otherwise affects the variable in any case.

While that's a pretty big number of syntactical forms, use of such forms can help make a programmer's intentions clear. If a number of places within a method each use let q=something; but the usages of q are all cleanly distinct, that can be easier to read than having code use a different name for each q, or having a single declaration for q up top (but then not knowing whether it's supposed to be possible for execution to skip over code that assigns q's value and then read the previous value q held. Having separate syntax for let, declare, and def should make program intentions clearer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.