Dynamism — allowing definitions to be replaced in a running program — is a hugely convenient feature, because it can shorten the edit-test loop by so much. But like many powerful features, it makes some errors harder to detect — in this case, name collisions. It's easy to catch these automatically in a static language: simply make redefinition of an existing variable an error. But in a dynamic language, redefinition is a feature, so we can't simply reject it. We can give a warning, so collisions won't go undetected, but this will annoy users whenever they interactively redefine something. Can we do better?
In some Lisps,
defvar has a related problem, and illustrates a possible solution. Its purpose is to create a (global) variable with a given initial value. There's a problem with redefining: what do you do if the variable already exists, and has a different value?
In both Common Lisp and Emacs Lisp,
defvar has the curious feature that it sets the variable only if it doesn't already have a value — if it already exists, it's not changed. This is intended to make re-
loading sourcefiles safe: otherwise, it would reset your global variables.
If you think this is surprising behavior, you're not alone. Alan Crowe once suggested that it would be less confusing if
defvar were called something like
def-perv-noclobber instead, because neither its pervasive
specialness nor its clobber-avoidance are what you would expect from something called
defonce is a better name.)
When a user reevaluates a single
defvar interactively, however, they probably do want to clobber the value, or they wouldn't bother. Both Emacs and Slime therefore have a special case: when a
defvar is evaluated interactively (as by C-M-x), it will clobber any existing value. This is ugly, of course, but like C-t's irregular behaviour at end-of-line, it does what the user wants.
Something similar might be useful for detecting errors of redefinition. Can we allow redefinitions when a definition is evaluated interactively, but not when it's loaded as part of a file? No, because it's normal to reload a source file after editing it, which replaces every definition in the file, but shouldn't produce any warnings. Nor should we disable the warning for all interactive evaluation, including
load, because that's when the warnings are most useful. Interactivity alone is not a sufficient reason to suppress warnings.
What we really want is to warn about redefinition only within a single interactive operation. It's generally OK for a
load to replace old definitions; it's only suspicious if a definition is made twice without user intervention. So if a name is defined twice in a single
load (directly, or in any other files it loads), that's an error or warning, but when it's defined twice in two separate batches, that's OK. This is easy to implement (by e.g. recording each definition made in the current
load), and gives much more precise warnings.