Re: Values and objects

2014-05-17 Thread Albert van der Horst
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

2014-05-11 Thread Marko Rauhamaa
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

2014-05-11 Thread Steven D'Aprano
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

2014-05-11 Thread Rustom Mody
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

2014-05-11 Thread Steven D'Aprano
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

2014-05-11 Thread Steven D'Aprano
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

2014-05-11 Thread Jussi Piitulainen
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

2014-05-11 Thread Rustom Mody
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

2014-05-11 Thread Jussi Piitulainen
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

2014-05-11 Thread Steven D'Aprano
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

2014-05-11 Thread Rotwang

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

2014-05-11 Thread Rustom Mody
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

2014-05-11 Thread Marko Rauhamaa
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

2014-05-11 Thread Marko Rauhamaa
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

2014-05-11 Thread Ned Batchelder

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

2014-05-11 Thread Marko Rauhamaa
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

2014-05-11 Thread Rotwang

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

2014-05-10 Thread Steven D'Aprano
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

2014-05-10 Thread Chris Angelico
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

2014-05-10 Thread Marko Rauhamaa
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

2014-05-10 Thread Jussi Piitulainen
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

2014-05-10 Thread Steven D'Aprano
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

2014-05-10 Thread Chris Angelico
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

2014-05-10 Thread Ethan Furman

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

2014-05-10 Thread MRAB

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

2014-05-10 Thread Ethan Furman

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

2014-05-10 Thread Terry Reedy

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

2014-05-10 Thread Terry Reedy

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

2014-05-10 Thread Devin Jeanpierre
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

2014-05-10 Thread Chris Angelico
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

2014-05-10 Thread Ethan Furman

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

2014-05-10 Thread Chris Angelico
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

2014-05-10 Thread Steven D'Aprano
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

2014-05-10 Thread Steven D'Aprano
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

2014-05-10 Thread Chris Angelico
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

2014-05-10 Thread Steven D'Aprano
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

2014-05-10 Thread Chris Angelico
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

2014-05-10 Thread 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. 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

2014-05-10 Thread Ethan Furman

[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

2014-05-10 Thread Ethan Furman

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]

2014-05-09 Thread Mark H Harris

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

2014-05-09 Thread Marko Rauhamaa
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

2014-05-09 Thread Ben Finney
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

2014-05-09 Thread Steven D'Aprano
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

2014-05-09 Thread Chris Angelico
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

2014-05-09 Thread Rustom Mody
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

2014-05-09 Thread Chris Angelico
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

2014-05-09 Thread Rustom Mody
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

2014-05-09 Thread Mark H Harris

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