I don't remember whether it is Javascript or PHP that uses dynamic
binding, but whichever it is, it is generally considered to be a bad
idea, at least as the default or only behaviour.
Bash is another language with dynamic binding. Some very old versions of
Lisp use dynamic binding, because it was the easiest to implement. Most
modern languages use lexical (also known as static) binding, because it
is more sensible.
Here is an illustration of the difference: suppose we have two modules,
library.py and main.py:
# library.py
x = 23
def func(y):
return x + y
# main.py
import library
x = 1000
print func(1)
If main.py prints 24 (and it does), then Python is using lexical scoping.
But if it prints 1001 (which it doesn't), then it is using dynamic
scoping. The obvious problem with dynamic binding is that the behaviour
of a function may vary depending on where you call it.
I don't believe that dynamic vs. lexical binding is what rusi was
attempting to describe. If he was, then Python and Haskell would be a
bad comparison since both are lexical. Rather, I think what he was
trying to show was capture by reference vs. capture by value in the
context of closures. Python uses capture by reference, and so the
upvalue is the value of that reference at the time the closure is
called. Haskell uses capture by value, and the upvalue is the value at
the time of definition.
I don't think "by reference" versus "by value" are good terms to use
here, since they risk conflating the issue with "call by reference"
versus "call by value" semantics. I prefer "late" versus "early", as you
suggest below.
I've also seen the distinction described as "early" vs. "late" binding
on this list, but I'm not sure how precise that is -- I believe that
terminology more accurately describes whether method and attribute names
are looked up at compile-time or at run-time,
Not necessarily *compile* time, but the distinction is between when the
function is defined (which may at compile time, or it may be at run time)
versus when the function is called. I think that gets to the heart of the
issue, not whether the capture copies a value or a reference. At some
point, the capture must make use of the value: whether it does so via a
direct C-style memory location copy, or an object pointer, or some other
mechanism, is irrelevant. What matters is whether that value is grabbed
at the time the closure is created, or when the closure is called.
late binding being the
feature that makes duck typing possible.
That is conflating two entirely distinct subjects. Python 1.5 had duck-
typing but no closures, so the one certainly does not depend on the other.
Duck-typing is more a philosophy than a language feature: the language
must be typed, and the programmer must prefer to program to a protocol or
a specification rather than to membership of a type.