Steven D'Aprano <st...@remove-this-cybersource.com.au> wrote: > (3) Those who come from an entirely different programming model, say, > Forth or Haskell. For them, Python's assignment model is going to be the > least of their worries.
Actually, Haskell's assignment model (you have to grubbing about for IORefs or STRefs to find it but it's there) is exactly the same as Lisp, Scheme, Python, Dylan, Perl, Lua, Icon, Ruby, Erlang, ML, ... The variables-and-containers-hold-references-to-objects idea is common to a very large number (probably the majority? depends how you count) of high-level languages. Java is in the same category. C# is definitely not, since `struct's are composite, mutable value types clearly distinguishable from anything Python can do. The main dissent is probably from Tcl, which pretends to copy values -- even complex objects such as lists -- wholesale (though actually does fancy copy-on-write things under the covers). > Your first post in this topic made the extraordinarily arrogant and > incorrect claim that: > > [quote] > What the Python community often overlooks, when this discussion again > rears its ugly head (as it seems to every other hour or so), is that > its assignment model is BIZARRE, as in it's conceptually different > from virtually all other languages substantially taught in > undergraduate computer science programs. > [end quote] > > We can see some pretty poor assumptions right there: > > * That the Python community is capable of uniformly overlooking Python's > differences from other languages. > > * That only languages "substantially taught" in undergraduate CS courses > matter. And a massive assumption about the languages taught to CS undergrads too. In particular, Scheme is a fairly popular language to teach to undergrads, often as a first language. See, for example, `The Structure and Interpretation of Computer Programs' by Abelson and Sussman, and the (much more recent) `How to Design Programs' by Felleisen, Findler, Flatt and Krishnamurthi. > It seems that you don't include in the Python community all those who > use the term "name binding" instead of variable assignment > specifically because it gives new users a clue that Python is not the > same as C. Unfortunately, this practice causes other confusion, since `binding' is often used (in other language communities, notably Lisp and the functional languages) to describe the association between names and slots that hold references. Let me explain. I'll try to be clear, though I know that Stephen already understands this stuff well. At run-time, each named variable denotes a storage area (I'll call it a slot[2]) which holds a reference to some object[1]. +-----+ name ----> | ref -----> object +-----+ If we `assign' a different object to the variable, what really happens is that the slot is modified to refer to the other object; but the name continues to denote the same slot. Usually `binding', or `rebinding', a name describes a different process, whereby the name (for a while) denotes a different slot. This name-to- slot mapping is important because it's the mapping which is inherited by nested functions. This is most clearly shown by example. Consider this Python interaction. In [1]: l = [] In [2]: for i in [1, 2, 3]: ...: l.append(lambda: i) ...: In [3]: [f() for f in l] Out[3]: [3, 3, 3] This prints [3, 3, 3]. What's happened is that the lambdas have closed over the prevailing /binding/ of i -- i.e., which reference slot it denotes. Since the for loop operates by assignment, and /not/ by rebinding i, the three lambdas all closed over the same environment, and return the same value. Scheme's DO loop, by contrast, really does operate by binding. Consider this example of a GNU Guile interaction. guile> (define l '()) guile> (do ((i (list 1 2 3) (cdr i))) ... ((null? i)) ... (set! l (append l (list (lambda () (car i)))))) guile> (map (lambda (f) (f)) l) $1 = (1 2 3) That is, each time through the loop, the variable I denotes a /different/ reference slot; the LAMBDAs close over different environments, and the functions return different values. (This example illustrates both binding and assignment, since the SET! changes the value referred to in the slot denoted by L, without rebinding L.) A very approximate translation of the above into Python looks like this. In [1]: l = [] In [2]: items = [1, 2, 3] In [3]: def _loop(ix): ...: if ix >= len(items): return ...: l.append(lambda: items[ix]) ...: _loop(ix + 1) ...: In [4]: _loop(0) In [5]: [f() for f in l] Out[5]: [1, 2, 3] (I've cheated and used indices because Python lists don't have the head/tail structure of Lisp lists.) None of this is a criticism of Python's behaviour. (Sometimes it'd be nice if `for' worked by rebinding, but sometimes it's better that it doesn't.) But it is a criticism of the Python community's confusing use of the word `binding' to mean something different from what fairly closely-related communities use it to mean. [1] Lisp has a notion of `unbound variables', which is another confusing use of the terminology. What this usually means is that the variable really refers to a special value, and the run-time signals an error if it retrieves this value from a variable. [2] `Slot' gets used a lot too. Sorry. This usage has nothing to do with Lisp's structure or instance slots, and nothing to do with Python's __slots__. > You've also missed out on probably twenty years of CS where Java (using > the same assignment model as Python!) has been *the* language of choice > for undergrad CS, not to mention those introductory courses which use > Python. There's no way that Java has been taught anywhere for 20 years. It just isn't old enough. Wikipedia claims that Java appeared in 1995, which looks right to me. Python, released in 1991, is therefore older. > > And then you're shocked, SHOCKED!!! that people respond sharply. > > How different do you think the response would have been if you had said: > > "What we in the Python community should try to remember is that for those > new to the language, there can sometimes be preconceived ideas about how > assignment works that clashes with Python's assignment model. From my own > perspective, I found the differences between Python's name binding model > and the named-bins model of C/Pascal/Fortran confusing at first, and to > be honest, I still get caught by those differences. Naturally this is a > general problem for every language, Python is hardly unique, but please > remember not to bite the newbies just because they are still thinking in > some other language." > > -- [mdw] -- http://mail.python.org/mailman/listinfo/python-list