Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

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:

print(hi)
  • 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)

However,

  • 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

But

  • 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.

share|improve this question
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. –  Jörg W Mittag Mar 14 '12 at 1:35
add comment

1 Answer

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) {
  alert(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.

share|improve this answer
    
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. –  delnan Mar 13 '12 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). –  Tikhon Jelvis Mar 13 '12 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. –  delnan Mar 13 '12 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? –  Seth Carnegie Mar 14 '12 at 1:13
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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