Re: Values and objects
In article 536decca$0$29980$c3e8da3$54964...@news.astraweb.com, SNIP Personally, I don't imagine that there ever could be a language where variables were first class values *exactly* the same as ints, strings, floats etc. Otherwise, how could you tell the difference between a function which operated on the variable itself, and one which operated on the value contained by the value? The best you can do is for variables to be second class -- you can do these things to them, but you need special syntax or declarations to tell the compiler you're operating on the variable rather than the variable's value. E.g. Pascal and Algol have syntax for instructing the compiler when to pass a variable as a value, and when to pass the value. C gives you nothing. You're talking about Algol, but there is a great distinction between Algol60 and Algol68. Algol68 through the ref keyword goes a long way towards making variables first class citizens. E.g. although `` int i'' in Algol68 means practically the same as in C, it is defined as being an abbreviation of 'ref' 'int' i = 'loc' 'int'; This means so much that i is a reference to an otherwise unnamed int that is allocated locally. Furthermore you can't break the tie between i and that int (because you use =, you could have used := ) Because I refers to that location you can change it by i:=1; Note that the left side *must* be a reference. You can't change an int, you can only change the content of a memory place you can refer to. Now you can define 'ref' 'int' pi; pi := i; van Wijngaarden and crue pretty much nailed it, IMO. SNIP -- Steven D'Aprano http://import-that.dreamwidth.org/ Groetjes Albert -- Albert van der Horst, UTRECHT,THE NETHERLANDS Economic growth -- being exponential -- ultimately falters. albert@spearc.xs4all.nl =n http://home.hccnet.nl/a.w.m.van.der.horst -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
Rustom Mody rustompm...@gmail.com: On Saturday, May 10, 2014 2:39:31 PM UTC+5:30, Steven D'Aprano wrote: Personally, I don't imagine that there ever could be a language where variables were first class values *exactly* the same as ints, strings, floats etc. [...] What you mean by *exactly* the same mean, I am not sure... Lisp variables (symbols) are on an equal footing with other objects. IOW, lisp variables are objects in the heap. Marko -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On Sat, 10 May 2014 22:42:13 -0700, Ethan Furman wrote: On 05/10/2014 10:22 PM, Chris Angelico wrote: It's that declaration that creates the variable, not changing locals(). A Python variable is a name bound to a value (and values, of course, are objects). If you don't have both pieces, you don't have a Python variable. +1 Well said. -- Steven D'Aprano http://import-that.dreamwidth.org/ -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On Sunday, May 11, 2014 11:51:59 AM UTC+5:30, Marko Rauhamaa wrote: Rustom Mody : On Saturday, May 10, 2014 2:39:31 PM UTC+5:30, Steven D'Aprano wrote: Personally, I don't imagine that there ever could be a language where variables were first class values *exactly* the same as ints, strings, floats etc. [...] What you mean by *exactly* the same mean, I am not sure... Lisp variables (symbols) are on an equal footing with other objects. IOW, lisp variables are objects in the heap. But is a symbol a variable?? Sure, by providing a data-structure symbol, lisp provides one of the key building blocks for developing language processing systems. However I would argue that a variable is not a merely a symbol (identifier in more usual programming language-speak) but a relation between identifiers/symbols and some 'rhs' For an (interpreted?) language like python, rhs is naturally value/object For a C like language it is memory. [Just invoking the standard denotational semantics fare: Env : Symbol → Value for interpreted languages For 'compiled' languages Env : Symbol → Location (at compile time) Store : Location → Value (at run time) -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On Sat, 10 May 2014 18:28:43 -0700, Ethan Furman wrote: On 05/10/2014 04:18 PM, Chris Angelico wrote: On Sun, May 11, 2014 at 5:10 AM, Ethan Furman et...@stoneleaf.us wrote: And if you don't like that argument (although it is a perfectly sound and correct argument), think of the module name space: ret = spam spam = 23 will net you a simple NameError, because spam has not yet been created. What about this, though: ret = int int = 23 That will *not* net you a NameError, because 'int' exists in an outer scope (builtins). You can create a new module-scope variable and it will immediately begin to shadow a builtin; you can delete that variable and it will immediately cease to shadow that builtin. That's the difference I'm talking about. With function-local variables, they all have to exist (as other responses confirmed, that *is* a language guarantee), even though some of them aren't bound to anything yet. Well, with function variables they have to exist *when you use them*. ;) This seems like more of a scoping issue than a can we create variables in Python issue. Correct. The first line ret = int does a name lookup for int, finds it in the built-ins, and binds it to ret. The second line int = 23 binds the object 23 to the name int in the current namespace, i.e. the globals. It has nothing to do with how variables are created. By default, you can't do that inside a function because function scoping is special, not because function locals are kept inside slots. (1) They aren't always, not even in CPython, and (2) even if they are, an implementation could hide that fact and provide the same behaviour. I say by default because with byte-code hacking you can. Suppose I write the function: def special(): spam = spam process(spam) Under normal circumstances, this will fail, because the assignment spam = ... tells the compiler that spam is a local, and so the lookup for ... = spam does a LOAD_FAST which fails. But if I hack the byte code, I can turn that LOAD_FAST into a LOAD_GLOBAL, which then gives behaviour just like Lua: spam (the local variable) = spam (the global variable) Of course, this isn't a feature of Python the language. But with sufficient byte-code hacking skills, it is possible. I am curious, though, what other python's do with respect to function variables. As far as I know, Jython and IronPython store them in a dict namespace, just like globals. See my previous responses to Chris. -- Steven D'Aprano http://import-that.dreamwidth.org/ -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On Sun, 11 May 2014 11:59:21 +1000, Chris Angelico wrote: On Sun, May 11, 2014 at 11:28 AM, Ethan Furman et...@stoneleaf.us wrote: Well, with function variables they have to exist *when you use them*. ;) This seems like more of a scoping issue than a can we create variables in Python issue. I am curious, though, what other python's do with respect to function variables. Variables exist in scope. Apart from assembly language, where registers have universal scope, every language I know of has some concept of scope. BASIC. (REXX is very different from most, in that PROCEDURE EXPOSE isn't at all your classic notion of scoping, but there's still the concept that there can be two variables with the same name.) When you create one, you create it in a particular scope, and that's how it must be. Yes. But when do you create it? At declaration time, or when a value is bound to it? # Ensure spam does not exist. try: del spam except NameError: pass assert spam not in globals() # Declare spam. global spam print (spam in globals()) # prints False print (spam) # raises NameError The same applies to locals. Whether a slot is pre-allocated or not, the variable doesn't exist until there is a value bound to the name. -- Steven D'Aprano http://import-that.dreamwidth.org/ -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
Marko Rauhamaa writes: Rustom Mody: On Saturday, May 10, 2014 2:39:31 PM UTC+5:30, Steven D'Aprano wrote: Personally, I don't imagine that there ever could be a language where variables were first class values *exactly* the same as ints, strings, floats etc. [...] What you mean by *exactly* the same mean, I am not sure... Lisp variables (symbols) are on an equal footing with other objects. IOW, lisp variables are objects in the heap. Only some, or only in quite old or special members of the family. But yes, I suppose when Lisp was still LISP, it was the kind of language that Steven fails to imagine in the quotation above. Variables really were symbols, which still are objects that can be passed around and stored in data structures. Or maybe not - wasn't the essential binding component (originally an association list, later a more abstract environment, called namespace in Python culture) separate from the symbol even then? Global bindings aside. But default in Common Lisp is lexical binding, and Scheme has only lexical bindings. An ordinary lexical variable is not an object in any reasonable sense that I can see. (let ((f (let ((x 3)) (lambda () x ;; The binding of x is still relevant here but not in scope and not ;; accessible through the symbol x (funcall f)) ;== 3 # That's (lambda f : f())((lambda x : (lambda : x))(3)) #= 3 # Roughly, f = (lambda x : (lambda : x))(3) ; f() #= 3 -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On Sunday, May 11, 2014 1:56:41 PM UTC+5:30, Jussi Piitulainen wrote: Marko Rauhamaa writes: Rustom Mody: On Saturday, May 10, 2014 2:39:31 PM UTC+5:30, Steven D'Aprano wrote: Personally, I don't imagine that there ever could be a language where variables were first class values *exactly* the same as ints, strings, floats etc. [...] What you mean by *exactly* the same mean, I am not sure... Lisp variables (symbols) are on an equal footing with other objects. IOW, lisp variables are objects in the heap. Only some, or only in quite old or special members of the family. But yes, I suppose when Lisp was still LISP, it was the kind of language that Steven fails to imagine in the quotation above. Variables really were symbols, which still are objects that can be passed around and stored in data structures. Or maybe not - wasn't the essential binding component (originally an association list, later a more abstract environment, called namespace in Python culture) separate from the symbol even then? Global bindings aside. A symbol is a first-class data structure in any lisp (that I know) http://en.wikipedia.org/wiki/Homoiconicity is a defining characteristic of lisp Environments are first class in many schemes: http://sicp.ai.mit.edu/Fall-2004/manuals/scheme-7.5.5/doc/scheme_14.html (The '+'es there indicate its an MIT scheme extension; but its quite common) In my understanding a symbol can be called a variable only wrt some environment IOW there is no meaning to the word 'variable' without some notion of scope. I am not sure what your references to old and new lisps and static vs dynamic scope has to do with this. Or are you saying that in the 1960s lisps, a symbol was the string (name) along with its (dynamic binding) stack?? Python to qualify for this not only would the namespacing of locals have to be systematic with globals, the nesting structure of environments would have to be introspectively available as in the scheme example. Note the functions: environment-parent and environment-bound-names -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
Rustom Mody writes: On Sunday, May 11, 2014 1:56:41 PM UTC+5:30, Jussi Piitulainen wrote: Marko Rauhamaa writes: Rustom Mody: On Saturday, May 10, 2014 2:39:31 PM UTC+5:30, Steven D'Aprano wrote: Personally, I don't imagine that there ever could be a language where variables were first class values *exactly* the same as ints, strings, floats etc. [...] What you mean by *exactly* the same mean, I am not sure... Lisp variables (symbols) are on an equal footing with other objects. IOW, lisp variables are objects in the heap. Only some, or only in quite old or special members of the family. But yes, I suppose when Lisp was still LISP, it was the kind of language that Steven fails to imagine in the quotation above. Variables really were symbols, which still are objects that can be passed around and stored in data structures. Or maybe not - wasn't the essential binding component (originally an association list, later a more abstract environment, called namespace in Python culture) separate from the symbol even then? Global bindings aside. A symbol is a first-class data structure in any lisp (that I know) http://en.wikipedia.org/wiki/Homoiconicity is a defining characteristic of lisp I don't see the relevance of these observations. The claim was that Lisp variables are symbols. What do you write in Common Lisp in place of the ... to have the following evaluate to the the value of the variable x? (let ((x (f)) (y 'x)) (... y ...)) No, (eval y) is not an answer, and (symbol-value y) is not an answer: these do not do the thing at all. To suggest (progn y x) is to concede my point that there is no way to get the value of x through the symbol x that is the value of y. Environments are first class in many schemes: http://sicp.ai.mit.edu/Fall-2004/manuals/scheme-7.5.5/doc/scheme_14.html (The '+'es there indicate its an MIT scheme extension; but its quite common) It's not very common. A couple of top-level environment specifiers are in the reports (scheme-report-environment, null-environment, and interaction-environment is optional, if I recall correctly) but the crucial reifier of an arbitrary lexical environment is not, and environment specifiers can only be used as an argument to eval. Even if that were common, it seems to me a joke to say that the symbol itself is the variable, which is the claim that I responded to. It's like saying that pairs of integers are first class variables because they can be interpreted as lexical addresses wrt an environment. You know, (0, 0) refers to the first variable in the current environment frame, (3, 1) to the second variable in a specific ancestor frame, and so on. In my understanding a symbol can be called a variable only wrt some environment IOW there is no meaning to the word 'variable' without some notion of scope. Agreed. So you consider it reasonable to say that variables are symbols in Lisp, and then clarify that a symbol means a symbol together with a first-class lexical environment, as if that was implicit in the original claim (and as if such environments were widely available in Lisp)? If so, I admit I've been fooled, and I've spent far too much time on this already. At least I was responding in good faith. I am not sure what your references to old and new lisps and static vs dynamic scope has to do with this. I'm saying that lexical variables are not accessible through the symbol that happens to look like the variable in the source code. And I'm saying that it's the lexical variables that need to be considered, because they are the default kind even in Lisp today. Dynamic variables are special. (They are even _called_ special.) I'm not saying that a dynamic variable cannot be accessed through the symbol, because that doesn't seem to be true. (I installed a Common Lisp and experimented a little when I wrote my original response.) Or are you saying that in the 1960s lisps, a symbol was the string (name) along with its (dynamic binding) stack?? It seems to be the case today, in Common Lisp, that a special variable is accessible through the symbol. For example, (symbol-value y) would work in my example above if x had been declared special. The dynamic environment is implicit. In the 1960s, before Scheme AFAIUI, things were that way. Python to qualify for this not only would the namespacing of locals have to be systematic with globals, the nesting structure of environments would have to be introspectively available as in the scheme example. Note the functions: environment-parent and environment-bound-names If Marko meant MIT Scheme when he said Lisp, and reification of arbitrary lexical environments when he said symbol, I've responded to a quite different claim than he intended, and spent far too much effort on this. -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On Sun, 11 May 2014 11:26:41 +0300, Jussi Piitulainen wrote: Marko Rauhamaa writes: Rustom Mody: On Saturday, May 10, 2014 2:39:31 PM UTC+5:30, Steven D'Aprano wrote: Personally, I don't imagine that there ever could be a language where variables were first class values *exactly* the same as ints, strings, floats etc. [...] What you mean by *exactly* the same mean, I am not sure... Lisp variables (symbols) are on an equal footing with other objects. IOW, lisp variables are objects in the heap. Only some, or only in quite old or special members of the family. But yes, I suppose when Lisp was still LISP, it was the kind of language that Steven fails to imagine in the quotation above. Variables really were symbols, which still are objects that can be passed around and stored in data structures. Or maybe not - wasn't the essential binding component (originally an association list, later a more abstract environment, called namespace in Python culture) separate from the symbol even then? Global bindings aside. I'm not sure if you are agreeing or disagreeing that variables are values in Common Lisp or not. First you say they are, they you say maybe not. The point is, it is *logically impossible* for a language to use precisely the same syntax for value-assignment and variable-assignment. Consider the variable called x, which is bound to the value 23. If the language has a single assignment operator or statement: let y := name; that cannot be used for *both* binding the value 23 to y and binding the variable x to y (making y an alias for x). To use Pascal as an example, you cannot use the same declaration for pass- by-value and pass-by-reference, one or the other must use different syntax. function foo(x: integer, var y: integer): integer; Given that declaration, and the function call foo(a, b), x is bound to the value of a, while y is bound to the variable b. In the case of Common List, I count at least four different assignment forms: set, setq, setf, psetq, let plus two unbinding forms: makunbound, fmakunbound but I don't know enough about Lisp to tell you which ones implement binding-to-values and which binding-to-variables, if any. -- Steven D'Aprano http://import-that.dreamwidth.org/ -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On 11/05/2014 04:11, Steven D'Aprano wrote: [...] And try running this function in both 2.7 and 3.3 and see if you can explain the difference: def test(): if False: x = None exec(x = 1) return x I must confess to being baffled by what happens in 3.3 with this example. Neither locals() nor globals() has x = 1 immediately before the return statement, so what is exec(x = 1) actually doing? -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On Sunday, May 11, 2014 6:21:08 PM UTC+5:30, Steven D'Aprano wrote: The point is, it is *logically impossible* for a language to use precisely the same syntax for value-assignment and variable-assignment. Consider the variable called x, which is bound to the value 23. If the language has a single assignment operator or statement: Its called set in classic lisp. Here's an emacs lisp session (the oldest lisp I can lay my hands on) The semicolons are comments like python's # *** Welcome to IELM *** Type (describe-mode) for help. ELISP (set (quote d) Hello World) Hello World ELISP (set (quote c) (quote d)) d ELISP ; those quote-s are getting boring ELISP (set 'b 'c) c ELISP ; once more short-form a very common case ELISP (setq a 'b) b ELISP ; Now unfold the chain ELISP ; Level 0 ELISP 'a a ELISP ; Level 1 ELISP a b ELISP ;Level 2 ELISP (eval a) c ELISP ;Level 3 ELISP (eval (eval a)) d ELISP ;Level 4 ELISP (eval (eval (eval a))) Hello World ELISP IOW set UNIFORMLY evaluates its 2 arguments. To get usual assignment like behavior of normal programming languages, one (typically) quotes the first argument. This is a sufficiently common case that it gets its own 'special form' -- setq (ie set-quote) However the more general case in which (the name of)* the variable is evaluated at run-time is always available. * Name of is strictly not correct because: ELISP (symbol-name 'a) a However if I dont say the name of... its hard to speak in an intelligible way. Here is the relevant intro from the elisp manual: A symbol in GNU Emacs Lisp is an object with a name. The symbol name serves as the printed representation of the symbol. In ordinary Lisp use, ... a symbol's name is unique--no two symbols have the same name. A symbol can serve as a variable, as a function name, or to hold a property list. Or it may serve only to be distinct from all other Lisp objects, so that its presence in a data structure may be recognized reliably. tl;dr: Quote-Eval go up and down the 'meta-language' tower just as Lambda-(function)Apply go up and down the functional tower. Elaborated further: http://blog.languager.org/2013/08/applying-si-on-sicp.html -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
Rustom Mody rustompm...@gmail.com: On Sunday, May 11, 2014 11:51:59 AM UTC+5:30, Marko Rauhamaa wrote: Lisp variables (symbols) are on an equal footing with other objects. IOW, lisp variables are objects in the heap. But is a symbol a variable?? Yes. A classic lisp symbol is even more variable than most other variables! It can hold *two* values. One is called a value binding and the other one the function binding. Scheme has unified the two; scheme symbols have only one value binding, which can be a function. Sure, by providing a data-structure symbol, lisp provides one of the key building blocks for developing language processing systems. However I would argue that a variable is not a merely a symbol (identifier in more usual programming language-speak) but a relation between identifiers/symbols and some 'rhs' The lisp symbol really is a data object with several fields: I can think of name, value, function and properties. They can be accessed with accessor functions. (Interestingly, scheme doesn't have the 'symbol-value accessor function of lisp's.) If lisp didn't have a way to rebind symbols (i.e., if it were purely functional and had no side effects), they wouldn't be so much variables as substitution spots in the code. For an (interpreted?) language like python, rhs is naturally value/object For a C like language it is memory. Symbols in lisp are memory slots, conceptually and physically. Marko -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
Jussi Piitulainen jpiit...@ling.helsinki.fi: The claim was that Lisp variables are symbols. What do you write in Common Lisp in place of the ... to have the following evaluate to the the value of the variable x? (let ((x (f)) (y 'x)) (... y ...)) No, (eval y) is not an answer, and (symbol-value y) is not an answer: these do not do the thing at all. I must admit I have never used Common Lisp. I can only guess from your question its symbol-value fetches the value from the global symbol table -- even if you replaced let with let* (the two x's are not the same symbol when let is used). I don't see any practical reason for that limitation. If you allow setq/setf/set!, you have no reason to disallow symbol-value on a local variable. Marko -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On 5/11/14 9:46 AM, Rotwang wrote: On 11/05/2014 04:11, Steven D'Aprano wrote: [...] And try running this function in both 2.7 and 3.3 and see if you can explain the difference: def test(): if False: x = None exec(x = 1) return x I must confess to being baffled by what happens in 3.3 with this example. Neither locals() nor globals() has x = 1 immediately before the return statement, so what is exec(x = 1) actually doing? The same happens if you try to modify locals(): def test(): ... if 0: x = 1 ... locals()['x'] = 13 ... return x ... test() Traceback (most recent call last): File stdin, line 1, in module File stdin, line 4, in test UnboundLocalError: local variable 'x' referenced before assignment The doc for exec says: Note: The default locals act as described for function locals() below: modifications to the default locals dictionary should not be attempted. Pass an explicit locals dictionary if you need to see effects of the code on locals after function exec() returns. The doc for locals says: Note: The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter. This is a tradeoff of practicality for purity: the interpreter runs faster if you don't make locals() a modifiable dict. -- Ned Batchelder, http://nedbatchelder.com -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
Marko Rauhamaa ma...@pacujo.net: I don't see any practical reason for that limitation. If you allow setq/setf/set!, you have no reason to disallow symbol-value on a local variable. In fact, the reason probably is practical and analogous to the locals() caveat in Python. If the language made local variables available indirectly, I'm guessing some optimizations would be much harder or impossible. In my own lisp implementation, where performance is not a concern at all, the local variables are both lexically scoped and offer access to symbol-value. Marko -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On 11/05/2014 19:40, Ned Batchelder wrote: On 5/11/14 9:46 AM, Rotwang wrote: On 11/05/2014 04:11, Steven D'Aprano wrote: [...] And try running this function in both 2.7 and 3.3 and see if you can explain the difference: def test(): if False: x = None exec(x = 1) return x I must confess to being baffled by what happens in 3.3 with this example. Neither locals() nor globals() has x = 1 immediately before the return statement, so what is exec(x = 1) actually doing? The same happens if you try to modify locals(): def test(): ... if 0: x = 1 ... locals()['x'] = 13 ... return x ... test() Traceback (most recent call last): File stdin, line 1, in module File stdin, line 4, in test UnboundLocalError: local variable 'x' referenced before assignment The doc for exec says: Note: The default locals act as described for function locals() below: modifications to the default locals dictionary should not be attempted. Pass an explicit locals dictionary if you need to see effects of the code on locals after function exec() returns. The doc for locals says: Note: The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter. This is a tradeoff of practicality for purity: the interpreter runs faster if you don't make locals() a modifiable dict. Thanks. -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On Sat, 10 May 2014 12:33:28 +1000, Chris Angelico wrote: On Sat, May 10, 2014 at 12:19 PM, Rustom Mody rustompm...@gmail.com wrote: For me, Marko's comment that variables in python are not first-class whereas in C they are is for me the most important distinction Ive seen (in a long time of seeing these discussions). https://en.wikipedia.org/wiki/First-class_citizen For variables in C to be considered first-class, they must, by most definitions, be able to be passed around as parameters and return values. Some definitions also require that they be able to be constructed at run-time. How do C variables shape up? 1) Passing them as parameters. You can pass a pointer to a variable, which is effectively the same as passing a variable to a function. No it is not. It is nothing like passing a variable to a function. You are passing a pointer, which is itself a value. True, it is a value which you, the author, gives meaning as a pointer to a variable, but that need not be the case. It might be a pointer to a part of an array, or a record, or to some random address in memory, or a dangling pointer. C allows you to perform arithmetic on pointers, which means you can construct pointers to nothing in particular. In C, pointers are first-class values, since you can: - construct pointers at runtime; - pass them to functions; - return them from functions; - assign them to variables; - stuff them in structs or arrays. But variables are not. You cannot create new variables, nor treat variables themselves as function arguments, or return them from functions. The closest you can do is *manually* use a pointer to a variable to simulate the same effect, but this is both too much and too little: - too much, because you aren't limited to passing pointers to a variable, you can pass pointers to anything you like, or nothing at all; - too little, because you are responsible for managing the pointers, instead of having the compiler do so. In Pascal, like C, you can't create new variables, or return them from functions, or embed them in records. But unlike C, you can pass them to functions, using a var parameter to use pass-by-reference. Algol is similar, except pass-by-name instead. I guess that makes Pascal variables second-and-a-half class values. Given: procedure foo(var inside: integer); begin {...} end; begin foo(outside); end. the global variable outside is passed to foo where it effectively becomes the local variable inside. Notice that we don't manually have to concern ourselves with pointers, in fact whether Pascal uses pointers to implement this or not is entirely invisible to the coder using the feature. It could be using magic fairy dust for all we know. We simply write the most direct, natural code we possibly can: foo(outside); and the compiler does whatever magic is needed to ensure the variable outside, rather than the value of outside, is passed to the procedure foo. There is nothing like that in C. You can only manually simulate it by passing a pointer to a variable, not by passing the variable itself. To argue that C pointers are pass by reference is like arguing that C has a garbage collector, because you can write one yourself. The callee can mutate your variable through the pointer. 2) Returning them. This is a lot more dodgy, owing to the dangling-pointer issue, but as long as you accept that the reference to a variable doesn't ensure its continued life, I suppose this might be acceptable. Maybe. But it's pushing it. 3) Constructing at run-time. Really REALLY pushing it. You can malloc and call that a variable, but it's not a variable any more, it's just a patch of memory. In fact, all this proves is that variables represent patches of memory, and patches of memory are first-class. It proves that pointers are first class (well, duh!). The C compiler makes very little effort to ensure that pointers actually point to anything. Nor can you create patches of memory (I'll like an extra couple of terrabytes please), or return them from functions, or insert them in arrays. Rather than *creating* patches of memory, malloc merely allocates it from pre-existing memory. Not liking the results here. You might just as well define that all Python variables must be backed by a dictionary (it's just as true as all C variables must be backed by memory) and then define the first-class-variable as a combination of a dict and a key. Python variables aren't first-class either, but in fact we can get a bit closer to first-class than either C or Pascal. Creating new variables is trivial. Since they don't need to be declared, you create a new variable just by assigning to it: try: spam except NameError: spam = 23 There are at least two other ways: globals()['spam'] = 23 exec('spam = 23') You can also delete variables: del spam Now this really shows first-class-ness. We
Re: Values and objects
On Sat, May 10, 2014 at 4:15 PM, Steven D'Aprano steve+comp.lang.pyt...@pearwood.info wrote: On Sat, 10 May 2014 12:33:28 +1000, Chris Angelico wrote: 1) Passing them as parameters. You can pass a pointer to a variable, which is effectively the same as passing a variable to a function. No it is not. It is nothing like passing a variable to a function. You are passing a pointer, which is itself a value. True, it is a value which you, the author, gives meaning as a pointer to a variable, but that need not be the case. It might be a pointer to a part of an array, or a record, or to some random address in memory, or a dangling pointer. C allows you to perform arithmetic on pointers, which means you can construct pointers to nothing in particular. I think at this point it's arguable, in that you can get so close to passing a variable to a function that it doesn't really matter about the distinction. But as I explained further down, it really just shows that patch of memory can be passed around, and that a variable can be backed by such a patch of memory. Rather than *creating* patches of memory, malloc merely allocates it from pre-existing memory. I disagree. On a modern system with memory management, malloc can grab memory from the system, thus making it available to your process. Sure, physical memory will normally have to have been installed in the system, but conceptually you could have a malloc function that actually freezes the program, asks the user to build a new computer and turn it on, connects to a new service on that computer, and allocates memory from there. As far as your program's concerned, malloc actually does (attempt to) give you more room than you had. Python variables aren't first-class either, but in fact we can get a bit closer to first-class than either C or Pascal. Creating new variables is trivial. Since they don't need to be declared, you create a new variable just by assigning to it: try: spam except NameError: spam = 23 No no no, this is really creating them at compile time. If you do this inside a function, the name has to be created as a local name before the function begins execution. There are at least two other ways: globals()['spam'] = 23 exec('spam = 23') With exec, you can do anything at run time. Does that mean that, in languages with an exec action, absolutely everything is first-class? I'm not sure that that counts. Maybe I'm wrong. Subscript-assigning to globals() is actually creating new (module-level) variables, though. And if Python allowed you to assign to locals() inside a function, then I would accept that local function variables can be created and destroyed at run time, but you can't, so local variables aren't first-class. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
Chris Angelico ros...@gmail.com: On Sat, May 10, 2014 at 8:34 AM, Marko Rauhamaa ma...@pacujo.net wrote: Right, Python's variables aren't like variables in C. Rather, Python's variables are like CPU registers. They cannot hold typed or structured objects and you can't pass references to them. Are you thinking that a Python variable is neither more nor less than what CPython implements them as? I was just being more Catholic than the Pope. To me, a variable is a variable is a variable. Marko -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
Marko Rauhamaa writes: To me, a variable is a variable is a variable. That works only in Python. Elsewhere, the sentence would be interpreted either as a variable is True or as a variable is False depending on whether a distinction without a difference is deemed helpful. -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On Sat, 10 May 2014 17:21:56 +1000, Chris Angelico wrote: On Sat, May 10, 2014 at 4:15 PM, Steven D'Aprano steve+comp.lang.pyt...@pearwood.info wrote: On Sat, 10 May 2014 12:33:28 +1000, Chris Angelico wrote: 1) Passing them as parameters. You can pass a pointer to a variable, which is effectively the same as passing a variable to a function. No it is not. It is nothing like passing a variable to a function. You are passing a pointer, which is itself a value. True, it is a value which you, the author, gives meaning as a pointer to a variable, but that need not be the case. It might be a pointer to a part of an array, or a record, or to some random address in memory, or a dangling pointer. C allows you to perform arithmetic on pointers, which means you can construct pointers to nothing in particular. I think at this point it's arguable, in that you can get so close to passing a variable to a function that it doesn't really matter about the distinction. But as I explained further down, it really just shows that patch of memory can be passed around, and that a variable can be backed by such a patch of memory. No offence Chris, but I think this demonstrates that learning C causes brain damage and prevents clear logical thinking :-P You're not passing a variable to a function. You're passing a pointer, which is itself a first-class value. It could be a pointer to ANYTHING, or NOTHING at all -- C doesn't even promise to ensure that it is a valid pointer, although more modern languages may. There's certainly no guarantee that it's a pointer to a variable. And you cannot create new variables -- C only allows variables to be created at compile time. The question is not, Can I implement some aspects of first-class behaviour for variables by hand? The question is, Are variables treated as first class values in C? If you asked, Does Pascal have an exponentiation or power operator?, and I answered Sure it does! If you want to calculate x squared, you just write x*x, if you want x cubed, write x*x*x, and if you want x to the power of twelve, x*x*x*x*x*x*x*x*x*x*x*x you would rightfully slap me with a halibut. Being able to manually perform repeated multiplication is not the same as having the language support exponentiation. To say nothing of fractional exponents. How about x to the power of one third? Being able to manually pass pointers to variables about is not the same as having first class variables. It fails on the very first hurdle, Are variables treated the same as other values? How do I pass an int to a function? func(some_int) How do I pass a double to a function? func(some_double) How do I pass a bool to a function? func(some_bool) How do I pass a variable to a function? ptr = some_variable; func(ptr) Does that look the same to you? The fact that you can do it at all is not sufficient to make it first class. It just makes it a work-around for the lack of first class variables in the language. Personally, I don't imagine that there ever could be a language where variables were first class values *exactly* the same as ints, strings, floats etc. Otherwise, how could you tell the difference between a function which operated on the variable itself, and one which operated on the value contained by the value? The best you can do is for variables to be second class -- you can do these things to them, but you need special syntax or declarations to tell the compiler you're operating on the variable rather than the variable's value. E.g. Pascal and Algol have syntax for instructing the compiler when to pass a variable as a value, and when to pass the value. C gives you nothing. I would say that C variables are *third class*. There's no compiler support for variables-as-values at all, but you can manually fake it a bit by using pointers. There is no way to tell whether the pointer actually points to a variable, and since arrays aren't first class neither are pointer-to-arrays. Algol and Pascal are *second class*, since the compiler does allow you to pass variables as arguments (var parameters in Pascal, I forget what they are called in Algol). Likewise, Python let's you create new variables at runtime, or delete them, but you can't pass them around. But still, you're quite limited in what the language does for you, compared to what you have to do yourself: x = 23 function(x, globals()) # See, I can pass a variable! Not. Rather than *creating* patches of memory, malloc merely allocates it from pre-existing memory. I disagree. On a modern system with memory management, malloc can grab memory from the system, thus making it available to your process. Sure, physical memory will normally have to have been installed in the system, but conceptually you could have a malloc function that actually freezes the program, asks the user to build a new computer and turn it on, connects to a new service on that computer, and allocates memory from there.
Re: Values and objects
On Sat, May 10, 2014 at 7:09 PM, Steven D'Aprano steve+comp.lang.pyt...@pearwood.info wrote: On Sat, 10 May 2014 17:21:56 +1000, Chris Angelico wrote: No offence Chris, but I think this demonstrates that learning C causes brain damage and prevents clear logical thinking :-P You're not passing a variable to a function. You're passing a pointer, which is itself a first-class value. It could be a pointer to ANYTHING, or NOTHING at all -- C doesn't even promise to ensure that it is a valid pointer, although more modern languages may. There's certainly no guarantee that it's a pointer to a variable. And you cannot create new variables -- C only allows variables to be created at compile time. The question is not, Can I implement some aspects of first-class behaviour for variables by hand? The question is, Are variables treated as first class values in C? Ehh... good point. I admit my brain damage - which, I have to say, has earned me a good portion of my life's salaries, so it's not useless :) Okay. So variables are not first-class in C. I still think memory blocks are pretty much first class, though; you can declare them at compile time (usually as an array of char or pointers) or at run time (with malloc or equivalent), and they can be passed to functions, returned from functions, etc. The only limitation is that a generic memory block doesn't maintain its size, so you can't distinguish between a char[10] and a char[1024]. Being able to manually pass pointers to variables about is not the same as having first class variables. It fails on the very first hurdle, Are variables treated the same as other values? How do I pass an int to a function? func(some_int) How do I pass a double to a function? func(some_double) How do I pass a bool to a function? func(some_bool) How do I pass a variable to a function? ptr = some_variable; func(ptr) Does that look the same to you? The fact that you can do it at all is not sufficient to make it first class. It just makes it a work-around for the lack of first class variables in the language. You can simply say func(some_variable), but yes, there is that difference. (This is how out parameters usually look in C. You stick ampersands in front of things.) And that's still passing memory blocks around, not variables. Rather than *creating* patches of memory, malloc merely allocates it from pre-existing memory. I disagree. On a modern system with memory management, malloc can grab memory from the system, thus making it available to your process. Sure, physical memory will normally have to have been installed in the system, but conceptually you could have a malloc function that actually freezes the program, asks the user to build a new computer and turn it on, connects to a new service on that computer, and allocates memory from there. As far as your program's concerned, malloc actually does (attempt to) give you more room than you had. Ha, well I guess you got me there. Perhaps a less over the top example is that you're running in a VM, and malloc can request more information from the host (which presumably has unlimited memory). Still impractical, but theoretically possible. Yeah. Completely impractical, but so is Post-It Note Python where everything's done with physical strings and sheets of paper. Thought experiments don't have to be performant :) Nevertheless, blocks of memory are not *first class* because you don't handle blocks of memory like other values. To make a new int variable, you declare it: int foo. To make a new block of memory, there is no declaration block foo. Rather, you call malloc() at runtime. And it might fail. int foo can never fail. As I mentioned above, you can make a new block of memory with char foo[1234]. And that's where a lot of buffer overruns come from, because someone thinks 1234 is *heaps* of space... but sometimes you really can know in advance how long something can be. (Maybe you're about to ask a file to give you the next 1233 bytes of content.) In this form, it's as safe as int foo - that is to say, safe unless your stack overflows, in which case all bets are off anyway. Python variables aren't first-class either, but in fact we can get a bit closer to first-class than either C or Pascal. Creating new variables is trivial. Since they don't need to be declared, you create a new variable just by assigning to it: try: spam except NameError: spam = 23 No no no, this is really creating them at compile time. It certainly isn't. Here's a slightly different demonstration of the same principle, this time inside a function to prove that there's nothing special about the global namespace: py def demo(): ... print('spam' in locals()) ... spam = 23 ... print('spam' in locals()) ... py demo() False True Tell me, what may this function do in a compliant Python? def demo(): ret = spam spam = 23 return ret In CPython, that'll raise
Re: Values and objects
On 05/10/2014 02:32 AM, Chris Angelico wrote: Tell me, what may this function do in a compliant Python? def demo(): ret = spam spam = 23 return ret In CPython, that'll raise UnboundLocalError, because the local variable 'spam' does already exist, and currently has no value (no object bound to it). No, it does not exist -- or, more accurately, it does not exist *yet* but will. The fact that there is a slot waiting for what will be spam is a cpython implementation detail. And if you don't like that argument (although it is a perfectly sound and correct argument), think of the module name space: ret = spam spam = 23 will net you a simple NameError, because spam has not yet been created. If a compliant Python implementation is allowed to have this return the value of a global or builtin spam, then I would agree that you can create variables at run time. See module example above. This behavior is not allowed in functions for scope and sanity (mostly sanity) reasons. -- ~Ethan~ -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On 2014-05-10 20:10, Ethan Furman wrote: On 05/10/2014 02:32 AM, Chris Angelico wrote: Tell me, what may this function do in a compliant Python? def demo(): ret = spam spam = 23 return ret In CPython, that'll raise UnboundLocalError, because the local variable 'spam' does already exist, and currently has no value (no object bound to it). No, it does not exist -- or, more accurately, it does not exist *yet* but will. The fact that there is a slot waiting for what will be spam is a cpython implementation detail. And if you don't like that argument (although it is a perfectly sound and correct argument), think of the module name space: ret = spam spam = 23 will net you a simple NameError, because spam has not yet been created. If a compliant Python implementation is allowed to have this return the value of a global or builtin spam, then I would agree that you can create variables at run time. See module example above. This behavior is not allowed in functions for scope and sanity (mostly sanity) reasons. UnboundLocalError is like NameError, except that Python knows that the name is local because somewhere in the function you're binding to that name and you haven't said that it's global or nonlocal. Having a different exception for that case makes it clearer to the user what the problem is. -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On 05/10/2014 12:22 PM, MRAB wrote: UnboundLocalError is like NameError, except that Python knows that the name is local because somewhere in the function you're binding to that name and you haven't said that it's global or nonlocal. Having a different exception for that case makes it clearer to the user what the problem is. Absolutely. At one point NameError was raised in both cases, which could be very confusing to track down. -- ~Ethan~ -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On 5/10/2014 3:10 PM, Ethan Furman wrote: On 05/10/2014 02:32 AM, Chris Angelico wrote: Tell me, what may this function do in a compliant Python? def demo(): ret = spam spam = 23 return ret In CPython, that'll raise UnboundLocalError, Note: issubclass(UnboundLocalError, NameError) True I am not sure if adding the specificity is helpful or not. because the local variable 'spam' does already exist, and currently has no value (no object bound to it). No, it does not exist -- or, more accurately, it does not exist *yet* but will. The fact that there is a slot waiting for what will be spam is a cpython implementation detail. And if you don't like that argument (although it is a perfectly sound and correct argument), think of the module name space: ret = spam spam = 23 will net you a simple NameError, because spam has not yet been created. In other words, those two lines raise a NameError in either case. -- Terry Jan Reedy -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On 5/10/2014 3:22 PM, MRAB wrote: UnboundLocalError is like NameError, More specifically, isinstance(UnboundLocalError(), NameError) True This means that 'except NameError:' clauses written before the UnboundLocalError subclass was added still work and do not necessarily need to be modified. (I am allowing for the possibility that the body of the clause tries to separate the specific error from other NameErrors). -- Terry Jan Reedy -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On Sat, May 10, 2014 at 12:10 PM, Ethan Furman et...@stoneleaf.us wrote: On 05/10/2014 02:32 AM, Chris Angelico wrote: Tell me, what may this function do in a compliant Python? def demo(): ret = spam spam = 23 return ret In CPython, that'll raise UnboundLocalError, because the local variable 'spam' does already exist, and currently has no value (no object bound to it). No, it does not exist -- or, more accurately, it does not exist *yet* but will. The fact that there is a slot waiting for what will be spam is a cpython implementation detail. The name of the exception is UnboundLocalError. And the message says that we referred to a local variable. Also see the language reference: When a name is not found at all, a NameError exception is raised. If the name refers to a local variable that has not been bound, a UnboundLocalError exception is raised. UnboundLocalError is a subclass of NameError. spam is referring to a local variable that has not been bound. This is not an implementation detail. And if you don't like that argument (although it is a perfectly sound and correct argument), think of the module name space: ret = spam spam = 23 will net you a simple NameError, because spam has not yet been created. Because module level variables work differently from local variables. -- Devin -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On Sun, May 11, 2014 at 5:10 AM, Ethan Furman et...@stoneleaf.us wrote: And if you don't like that argument (although it is a perfectly sound and correct argument), think of the module name space: ret = spam spam = 23 will net you a simple NameError, because spam has not yet been created. What about this, though: ret = int int = 23 That will *not* net you a NameError, because 'int' exists in an outer scope (builtins). You can create a new module-scope variable and it will immediately begin to shadow a builtin; you can delete that variable and it will immediately cease to shadow that builtin. That's the difference I'm talking about. With function-local variables, they all have to exist (as other responses confirmed, that *is* a language guarantee), even though some of them aren't bound to anything yet. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On 05/10/2014 04:18 PM, Chris Angelico wrote: On Sun, May 11, 2014 at 5:10 AM, Ethan Furman et...@stoneleaf.us wrote: And if you don't like that argument (although it is a perfectly sound and correct argument), think of the module name space: ret = spam spam = 23 will net you a simple NameError, because spam has not yet been created. What about this, though: ret = int int = 23 That will *not* net you a NameError, because 'int' exists in an outer scope (builtins). You can create a new module-scope variable and it will immediately begin to shadow a builtin; you can delete that variable and it will immediately cease to shadow that builtin. That's the difference I'm talking about. With function-local variables, they all have to exist (as other responses confirmed, that *is* a language guarantee), even though some of them aren't bound to anything yet. Well, with function variables they have to exist *when you use them*. ;) This seems like more of a scoping issue than a can we create variables in Python issue. I am curious, though, what other python's do with respect to function variables. -- ~Ethan~ -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On Sun, May 11, 2014 at 11:28 AM, Ethan Furman et...@stoneleaf.us wrote: Well, with function variables they have to exist *when you use them*. ;) This seems like more of a scoping issue than a can we create variables in Python issue. I am curious, though, what other python's do with respect to function variables. Variables exist in scope. Apart from assembly language, where registers have universal scope, every language I know of has some concept of scope. (REXX is very different from most, in that PROCEDURE EXPOSE isn't at all your classic notion of scoping, but there's still the concept that there can be two variables with the same name.) When you create one, you create it in a particular scope, and that's how it must be. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On Sun, 11 May 2014 09:18:34 +1000, Chris Angelico wrote: On Sun, May 11, 2014 at 5:10 AM, Ethan Furman et...@stoneleaf.us wrote: And if you don't like that argument (although it is a perfectly sound and correct argument), think of the module name space: ret = spam spam = 23 will net you a simple NameError, because spam has not yet been created. What about this, though: ret = int int = 23 That will *not* net you a NameError, because 'int' exists in an outer scope (builtins). You can create a new module-scope variable and it will immediately begin to shadow a builtin; you can delete that variable and it will immediately cease to shadow that builtin. Yes. That's part of documented language behaviour to do with scoping search paths. See below. That's the difference I'm talking about. With function-local variables, they all have to exist (as other responses confirmed, that *is* a language guarantee), even though some of them aren't bound to anything yet. Define exist. Just because a slot exists waiting for a variable, doesn't mean that the variable which would use that slot exists. Like dicts and lists, function locals() are over-allocated: CPython pre-allocates slots for locals based on compile-time information, even if those locals are never bound to and therefore don't exist: def demo(): if False: x = 23 print x # Fails You're trying to argue that because there is a slot for x, the variable x exists. But I think that is the wrong definition of exists. If you have a list L = [], would you say that L[4] exists because the array is over- allocated and already has (at least) four slots waiting to be used, but L[100] doesn't because it isn't over-allocated that much? What if the pre- allocation rules change? What if an implementation decides not to bother pre-allocating empty lists? What if an implementation pre-allocates a random number of array slots? Would you be comfortable saying that there is a 25% chance that L[4] exists and a 1% chance that L[100] exists? In both these cases, array slots in a list or dict, and locals, we risk mistaking implementation details for language features. I think you actually are making this error when it comes to locals. When talking about the implementation, it is relevant to discuss the existence of slots. But when talking about the language, about features visible from Python code such as variables (a.k.a. name bindings), local slots don't matter. Jython and IronPython don't (so far as I know) use them, and locals() happens to be writable. Here's an example from IronPython 2.6: def test(): ... if False: spam = None ... d = locals() ... d['spam'] = 23 ... return spam ... test() 23 And a similar example from Jython 2.5: def test(): ... locals()['spam'] = 42 ... return spam ... spam = None ... test() 42 Neither example works in CPython, you get an UnboundLocalError, but whether or not locals() is writable is is *explicitly* documented as an implementation detail. How implementations store local variables (in a dictionary like globals, slots, in the Cloud) is up to them, so long as the implementation follows the scoping rules. Python determines whether a variable is local or not at compile-time: (1) If a function contains a binding operation (assignment; import; del) on that variable, then the variable is defined as a local unless otherwise declared as a global or nonlocal (Python 3 only). (2) Otherwise it is not a local. (3) Outside of a function, it is a global whether declared as such or not. (4) Variables (names) don't exist until they have a value bound to them. I guess you want to challenge #4, and say that local variables exist as soon as the slot that holds them exists. I think that is wrong. And besides, even CPython 2 doesn't always use slots for locals: consider what happens when you use import * inside a function. And try running this function in both 2.7 and 3.3 and see if you can explain the difference: def test(): if False: x = None exec(x = 1) return x But I digress. Name look-ups for locals look only in the local scope. Name lookups for everything else search the chain nonlocals:globals:builtins. Name bindings (assignments, del, imports) for locals write only to the local scope. For globals they write only to the global scope and for nonlocals they write to the nearest enclosing nonlocal scope that already defines that variable. -- Steven D'Aprano http://import-that.dreamwidth.org/ -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On Sat, 10 May 2014 14:03:11 -0700, Devin Jeanpierre wrote: On Sat, May 10, 2014 at 12:10 PM, Ethan Furman et...@stoneleaf.us wrote: On 05/10/2014 02:32 AM, Chris Angelico wrote: Tell me, what may this function do in a compliant Python? def demo(): ret = spam spam = 23 return ret In CPython, that'll raise UnboundLocalError, because the local variable 'spam' does already exist, and currently has no value (no object bound to it). No, it does not exist -- or, more accurately, it does not exist *yet* but will. The fact that there is a slot waiting for what will be spam is a cpython implementation detail. The name of the exception is UnboundLocalError. And the message says that we referred to a local variable. Also see the language reference: When a name is not found at all, a NameError exception is raised. If the name refers to a local variable that has not been bound, a UnboundLocalError exception is raised. UnboundLocalError is a subclass of NameError. spam is referring to a local variable that has not been bound. This is not an implementation detail. Of course not. What is an implementation detail is that there is a slot waiting to be filled for it, just like Ethan said. It's the existence of pre-allocated slots for locals which is an implementation detail, not whether a name is treated as local or not. And if you don't like that argument (although it is a perfectly sound and correct argument), think of the module name space: ret = spam spam = 23 will net you a simple NameError, because spam has not yet been created. Because module level variables work differently from local variables. But that is an implementation detail. IronPython and Jython use an ordinary dict for local variable namespaces, just like globals. Consider this example from Jython: spam = def modify(namespace): ... namespace['spam'] = 42 ... def demo(): ... modify(locals()) ... spam = spam ... return spam ... demo() 42 -- Steven D'Aprano http://import-that.dreamwidth.org/ -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On Sun, May 11, 2014 at 1:17 PM, Steven D'Aprano steve+comp.lang.pyt...@pearwood.info wrote: But that is an implementation detail. IronPython and Jython use an ordinary dict for local variable namespaces, just like globals. Consider this example from Jython: spam = def modify(namespace): ... namespace['spam'] = 42 ... def demo(): ... modify(locals()) ... spam = spam ... return spam ... demo() 42 All you're proving here is that, in some Pythons, locals() is writeable. What happens if you remove the spam = spam line? Would demo() not then return spam from the global scope, because the variable does not exist at local scope? Every example you've shown is simply giving a value to something that you've created by the normal method of having an assignment inside the function. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On Sun, 11 May 2014 13:30:03 +1000, Chris Angelico wrote: On Sun, May 11, 2014 at 1:17 PM, Steven D'Aprano steve+comp.lang.pyt...@pearwood.info wrote: But that is an implementation detail. IronPython and Jython use an ordinary dict for local variable namespaces, just like globals. Consider this example from Jython: spam = def modify(namespace): ... namespace['spam'] = 42 ... def demo(): ... modify(locals()) ... spam = spam ... return spam ... demo() 42 All you're proving here is that, in some Pythons, locals() is writeable. What happens if you remove the spam = spam line? Would demo() not then return spam from the global scope, Yes, this. See my previous email, and take careful note of Rule #2: in the absence of a binding operation, variables are not treated as local. because the variable does not exist at local scope? No to this. Consider this example: spam = def modify(namespace): ... namespace['spam'] = 42 ... def demo2(): ... assert 'spam' not in locals() ... modify(locals()) ... assert 'spam' in locals() ... return spam ... demo2() This proves that the spam variable *does* exist in locals, but it is not seen because the return spam doesn't check the local scope, so it sees the global spam. Sadly, the version of Jython I have doesn't provide a working dis module, but if it did I expect it would show the equivalent of what CPython does: the first version uses LOAD_FAST to look up spam, and the second version used LOAD_GLOBAL (a misnomer since it doesn't *just* look up globals). Every example you've shown is simply giving a value to something that you've created by the normal method of having an assignment inside the function. Nonsense. Look at the original examples again, more closely. Here they are again, this time with comments: def test(): if False: spam = None # Dead code, never executed. d = locals() d['spam'] = 23 # Not a normal assignment. return spam def test(): locals()['spam'] = 42 # Not a normal assignment. return spam spam = None # Dead code. and from my reply to Devin: def modify(namespace): namespace['spam'] = 42 def demo(): modify(locals()) # Not an ordinary assignment. spam = spam # Where does the initial value of spam come from? return spam The *only* purpose of the dead code in the two test() functions is to force the compiler to use LOAD_FAST (or equivalent) rather than LOAD_GLOBAL. But they aren't ever executed. At no time do I use normal name binding assignment to create local variables. In the demo() function, if I expand the line spam = spam out: temp = spam # Look up of spam occurs first. spam = temp # Binding occurs second. the difficulty should be even more obvious. Where does the value of spam come from before the binding? The answer is that it comes from writing directly to the namespace (a dict). There is no fixed slot for spam waiting for a value, because Jython and IronPython don't use fixed slots. There's only a dict. If we were using globals, it would be be more obvious what was going on, and there would be no argument about whether or not a variable exists before you give it a value. The answer would be, of course it doesn't exist before it has a value. Python declarations (whether implicit or explicit) don't create variables, they just instruct the compiler how to perform lookups on them. # Global scope print spam # fails, because there is no spam variable yet spam in globals() # returns False globals()['spam'] = 42 # now it exists spam = spam # a no-op print spam It's only because CPython is special, and locals() is special, that the equivalent code is indeterminate inside functions. -- Steven D'Aprano http://import-that.dreamwidth.org/ -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On Sun, May 11, 2014 at 3:11 PM, Steven D'Aprano steve+comp.lang.pyt...@pearwood.info wrote: Nonsense. Look at the original examples again, more closely. Here they are again, this time with comments: def test(): if False: spam = None # Dead code, never executed. d = locals() d['spam'] = 23 # Not a normal assignment. return spam def test(): locals()['spam'] = 42 # Not a normal assignment. return spam spam = None # Dead code. The *only* purpose of the dead code in the two test() functions is to force the compiler to use LOAD_FAST (or equivalent) rather than LOAD_GLOBAL. In a C-like language, locals are created by a declaration, and assigned a value separately. In Python, locals are created by the presence of assignment within the function, which in simple cases coincides with giving the value to it; but guarding the assignment with if False prevents the giving of the value, while still being an assignment for the sake of creating a local variable. Same if the assignment happens further down, or even in the same statement (spam = spam). It's still an assignment, so it has the declarative effect of telling the compiler this is now local, unless declared global/nonlocal. It's that declaration that creates the variable, not changing locals(). ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On Saturday, May 10, 2014 2:39:31 PM UTC+5:30, Steven D'Aprano wrote: Personally, I don't imagine that there ever could be a language where variables were first class values *exactly* the same as ints, strings, floats etc. Otherwise, how could you tell the difference between a function which operated on the variable itself, and one which operated on the value contained by the value? Its standard fare in theorem proving languages - see eg twelf: https://www.cs.cmu.edu/~fp/papers/cade99.pdf where the distinction is made between variables in the meta-language (ie twelf itself) and variables in the the object theory What you mean by *exactly* the same mean, I am not sure... Also I note that I was not meaning first-classness of variables in C in that literal sense. Its just I consider them more first-class than say Pascal but less than say Lisp. [The wikipedia link that Chris posted links to an article that makes the claim that firstclassness is not really defined but can be used in a vague/relative way ] -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
[accidentally went off-list; sorry] On 05/10/2014 02:03 PM, Devin Jeanpierre wrote: spam is referring to a local variable that has not been bound. This is not an implementation detail. The implementation detail is that in cpython there is a spot already reserved for what will be the 'spam' variable, as opposed to the module level where no such spots are reserved. Because module level variables work differently from local variables. Not by language definition. There are pythons where modifying function locals works, but the working or not-working is not a language guarantee. -- ~Ethan~ -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On 05/10/2014 10:22 PM, Chris Angelico wrote: It's that declaration that creates the variable, not changing locals(). A Python variable is a name bound to a value (and values, of course, are objects). If you don't have both pieces, you don't have a Python variable. -- ~Ethan~ -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects [was Re: Pass variable by reference]
On 5/7/14 8:08 PM, Steven D'Aprano wrote: In Python, all values *are* objects. It isn't a matter of choosing one or the other. The value 1 is an object, not a native (low-level, unboxed) 32 or 64 bit int. Unlike C# or Java, there is no direct language facility to box native values into objects or unbox objects to native values. Yes. In the context of the rest of this discussion, this one point is just one of the many reasons why it is not helpful to think of Python's {name: object} relationship as 'variable -- value'. Typically when I think about variables (particularly from the past, say Pascal, Basic, C, Fortran, Cobol c) I am thinking about modeling memory is some way where the variable (some naming convention) is a value handle or value pointer of some chunk of memory (by type | length) --- where I am creating a 'box' into which I may place something (usually some native type). When I think of Python's 'variables' (and I don't believe Python has variables) I am now thinking of a naming convention (for handling objects) where I am not the least interested in modeling memory for native types. I am instead interested in modeling the real world (or subset) with object abstractions. I am no longer interested in creating a 'box' into which I may place some type. I don't need variables any longer for that purpose. What I want is some very efficient naming convention whereby I can handle the objects I am constructing (for whatever abstract purpose). If a programmer new to Python thinks in terms of 'variables' from C or Pascal, or Fortran or Basic, they will run into surprises when it comes to handling the {name: object} idea in Python. In fact, most of the time this debate comes up it is precisely that the new user is finding Python's 'variables' aren't behaving correctly or finding that they are not able to 'do' what they used to do (say) with C's variables. It really comes down to the definition of 'variable' and whether the language in question is modeling memory, or modeling object abstractions. marcus -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
Mark H Harris harrismh...@gmail.com: Typically when I think about variables (particularly from the past, say Pascal, Basic, C, Fortran, Cobol c) I am thinking about modeling memory is some way where the variable (some naming convention) is a value handle or value pointer of some chunk of memory (by type | length) --- where I am creating a 'box' into which I may place something (usually some native type). When I think of Python's 'variables' (and I don't believe Python has variables) I am now thinking of a naming convention (for handling objects) where I am not the least interested in modeling memory for native types. I am instead interested in modeling the real world (or subset) with object abstractions. I am no longer interested in creating a 'box' into which I may place some type. I don't need variables any longer for that purpose. What I want is some very efficient naming convention whereby I can handle the objects I am constructing (for whatever abstract purpose). Right, Python's variables aren't like variables in C. Rather, Python's variables are like CPU registers. They cannot hold typed or structured objects and you can't pass references to them. Marko -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
Marko Rauhamaa ma...@pacujo.net writes: Right, Python's variables aren't like variables in C. Rather, Python's variables are like CPU registers. What is the salient difference between those two? I don't see the point of the distinction. Why have you chosen an analogy – CPU registers – that still uses the misleading “copies in containers” model, rather than the “sticky-notes on objects” model? The latter more accurately describes Python's references. They cannot hold typed or structured objects This is quite false. Every object in Python is typed and structured, and to the extent that Python has “variables”, they always refer to a typed and structured object. -- \ “Do unto others twenty-five percent better than you expect them | `\ to do unto you. (The twenty-five percent is [to correct] for | _o__)error.)” —Linus Pauling's Golden Rule | Ben Finney -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On Sat, 10 May 2014 01:34:58 +0300, Marko Rauhamaa wrote: Right, Python's variables aren't like variables in C. Rather, Python's variables are like CPU registers. They cannot hold typed or structured objects Surely you cannot mean that? It is *trivially simple* to disprove that statement: py x = [1, 2, 3] # A structured object py type(x) # that has a type class 'list' and you can't pass references to them. That at least you have got right. -- Steven D'Aprano http://import-that.dreamwidth.org/ -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On Sat, May 10, 2014 at 8:34 AM, Marko Rauhamaa ma...@pacujo.net wrote: Right, Python's variables aren't like variables in C. Rather, Python's variables are like CPU registers. They cannot hold typed or structured objects and you can't pass references to them. Are you thinking that a Python variable is neither more nor less than what CPython implements them as? Because I can design you a 100% compliant Python implementation in which: * Objects are represented with pieces of paper * Object types are represented with 150GSM paper so it's easier to find (note that an object type, being itself an object, must be represented with paper) * Named attributes and numeric indices (__[gs]etitem__) are recorded with ink on the paper * References, including from an object to its type, are pieces of string linking an attribute to another object * None is, in the interests of performance, represented by a piece of string that dangles * Functions get compiled down to a byte-code stored on eighty-column punched card * Integers and strings are always interned * The image processing library is stored inside an actual pillowcase * The 'print' function results in a human being speaking, and 'input' waits for another human to speak, and constructs a string with what was said As far as I know, this could be done, and it would be perfectly compliant with all of Python. It'd be horrendously slow, but Python's specs never demand performance. It wouldn't have C-like variables, it wouldn't have pointers (assigning a = b means looking up b, finding which object the string connects to, gluing another string to that same object, and severing any previous connection from a), and it certainly wouldn't have 32-bit or 64-bit integers, or anything like that. (Not that CPython has anything of the sort, as of 3.0, but it's perfectly conceivable for a compliant Python to have an optimization whereby small integers are handled more efficiently. Again, the Python specs don't say either way.) So what is a variable in this Python? Well... exactly what it is in any other Python, because this is just as much Python as CPython, Jython, PyPy, or any other. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On Saturday, May 10, 2014 6:31:49 AM UTC+5:30, Steven D'Aprano wrote: On Sat, 10 May 2014 01:34:58 +0300, Marko Rauhamaa wrote: and you can't pass references to them. That at least you have got right. And that's Marko's main point Right, Python's variables aren't like variables in C. Rather, Python's variables are like CPU registers. They cannot hold typed or structured objects Surely you cannot mean that? It is *trivially simple* to disprove that statement: py x = [1, 2, 3] # A structured object py type(x) # that has a type class 'list' You missed the 'hold' For me, Marko's comment that variables in python are not first-class whereas in C they are is for me the most important distinction Ive seen (in a long time of seeing these discussions). In C a pointer is a 'pre-variable' in this sense: int i, *p; p = i after this i and *p are completely interchangeable However p can also refer to -- (contain?hold?) depends on which side of this debate you are -- an element of an array or struct p = some_array[some_index] p = some_struct.some_field And all the way to anonymity with p = malloc(sizeof(*p)) This is what makes p a kind of meta-variable: - it can 'contain' other variables - it can contain variale-ish things like array elements - it can contain new variables on the fly via malloc These possibilities dont exist in python -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On Sat, May 10, 2014 at 12:19 PM, Rustom Mody rustompm...@gmail.com wrote: For me, Marko's comment that variables in python are not first-class whereas in C they are is for me the most important distinction Ive seen (in a long time of seeing these discussions). https://en.wikipedia.org/wiki/First-class_citizen For variables in C to be considered first-class, they must, by most definitions, be able to be passed around as parameters and return values. Some definitions also require that they be able to be constructed at run-time. How do C variables shape up? 1) Passing them as parameters. You can pass a pointer to a variable, which is effectively the same as passing a variable to a function. The callee can mutate your variable through the pointer. 2) Returning them. This is a lot more dodgy, owing to the dangling-pointer issue, but as long as you accept that the reference to a variable doesn't ensure its continued life, I suppose this might be acceptable. Maybe. But it's pushing it. 3) Constructing at run-time. Really REALLY pushing it. You can malloc and call that a variable, but it's not a variable any more, it's just a patch of memory. In fact, all this proves is that variables represent patches of memory, and patches of memory are first-class. Not liking the results here. You might just as well define that all Python variables must be backed by a dictionary (it's just as true as all C variables must be backed by memory) and then define the first-class-variable as a combination of a dict and a key. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On Saturday, May 10, 2014 8:03:28 AM UTC+5:30, Chris Angelico wrote: 2) Returning them. This is a lot more dodgy, owing to the dangling-pointer issue, but as long as you accept that the reference to a variable doesn't ensure its continued life, I suppose this might be acceptable. Maybe. But it's pushing it. 3) Constructing at run-time. Really REALLY pushing it. You can malloc and call that a variable, but it's not a variable any more, it's just a patch of memory. In fact, all this proves is that variables represent patches of memory, and patches of memory are first-class. Not sure what the 'just' is emphasizing/delimiting. Consider: int i; int *pi; char *pc; pi = i; pc = pi; If your 'just' were just (excuse pun!) then *pi would be identical to *pc -- just the same patch of memory Not liking the results here. You might just as well define that all Python variables must be backed by a dictionary (it's just as true as all C variables must be backed by memory) and then define the first-class-variable as a combination of a dict and a key. Yes this is the rub. C pointers are first-class but half-assed due to dangling pointers -- (Function returning address of an automatic variale etc) Likewise python's name-spaces go almost all the way to first-classing variables but not quite as Marko discovered when locals() looks like a dict, waddles like a dict but does not quack like a dict. -- https://mail.python.org/mailman/listinfo/python-list
Re: Values and objects
On 5/9/14 10:05 PM, Rustom Mody wrote: Likewise python's name-spaces go almost all the way to first-classing variables but not quite as Marko discovered when locals() looks like a dict, waddles like a dict but does not quack like a dict. QOTWeekEnd -- https://mail.python.org/mailman/listinfo/python-list