Nested function scope problem

D

Dennis Lee Bieber

That is not true. It may be the case in a number of languages but
my experience with lisp and smalltalk, though rather limited,
says that no such memory location is implied with the word "variable"
in those languages and AFAIK they don't have a problem with the
word "variable" either.
I have no smalltalk experience, and my lisp goes back to a cassette
based version on a TRS-80 Model III...

Since, at that time at least, everything in lisp was a
tree-branching linked list I had trouble even considering setq to define
a "variable" -- it was closer to adding a name to a node of the lists...
<G> {Yes, that IS a very loose interpretation}

Does lisp permit one object to have multiple "variables" attached to
it -- that is, two or more names on one "object" (whatever the node
contains)... And if so, what happens if, say, the "object" had been a
scalar value "3.14159265436" perhaps and you make an "assignment" to one
of the names?
Neither are smalltalk and lisp variables. Neither are C-variables
local to functions.
Within the scope, C variables are fixed memory addresses -- that
address may change between function invocations, but it is always a
fixed offset from the stack frame, so the object represented by that
variable is at a fixed offset...
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 
D

Dennis Lee Bieber

It's the "for the most part" part that I was wondering about :)
Heh... That's me obscuring the fact that I haven't taken the time to
verify if there are any exceptions
Or said in another way: Everything is immutable, except that collections of
objects (classes, lists, etc) may provide means to rebind members, which
then can be considered means to change objects.
I won't argue...
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 
A

Antoon Pardon

Python objects can exist without a "variable" bound to them...
Though typically such would soon be garbage collected <G>

Well C++ objects can exist without a "variable" bound to them.
We just call them memory leaks said:
Traditional languages are the other way around... If a variable
exists, it may exist with no object/value (ie, it is uninitialized -- a
big problem in C).

What do you call traditional? Lisp is about as old as Fortran AFAIK.
Python names can not exist (and be used) without
being bound to some object (even None is a defined object). Attempting
to use a name that has not been bound gives you the "unbound local" type
problem.
Yes, some other languages do define special flag values so that they
can detect the usage of an uninitialized item... But the variable itself
exists regardless; you can not detach the object from the variable
(except by assigning something else to the variable).

I'm not so sure Python is that different. The fact that you get
an UnboundLocalError, instead of a NameError, suggests that in
the first case, the 'variable' already exists but is bound to
a "Not yet Bound" value. Not so long ago I was discussing some
implementation details of CPython and someone then said that
all local variables are entered into the local scope at call
time. This was to prevent the language to find variables
that are shadowed on a more global scope because the local
variable wasn't boud yet.
 
A

Antoon Pardon

Maybe this gets somewhere. Consider variable != constant. Python names are
variables in that what they refer to (what is associated with them through
a dict) can be changed, through various means (most commonly assignment).
They are also variables in that what they refer to (usually) can be
changed. Whether an assignment or some other command changes the reference
association or the referenced object is one of the confusing issues with
Python. But that doesn't make a variable less variable... :)

I think the important thing to remember is that the assignment in Python
is a alias maker and not a copy maker. In languages like C, Fortran,
pascal, the assignment makes a copy from what is on the righthand and
stores that in the variable on the lefthand. In languages like Lisp,
Smalltalk and Python, the assignment essentially makes the lefthand
an alias for the righthand.
 
A

Antoon Pardon

I have no smalltalk experience, and my lisp goes back to a cassette
based version on a TRS-80 Model III...

Since, at that time at least, everything in lisp was a
tree-branching linked list I had trouble even considering setq to define
a "variable" -- it was closer to adding a name to a node of the lists...
<G> {Yes, that IS a very loose interpretation}

Does lisp permit one object to have multiple "variables" attached to
it -- that is, two or more names on one "object" (whatever the node
contains)...

AFAIK, yes
And if so, what happens if, say, the "object" had been a
scalar value "3.14159265436" perhaps and you make an "assignment" to one
of the names?

About the same as happens in Python. One name will then be attached to
a new "value" and the other names will still be attached to "3.14159265436"
 
G

Gerhard Fiedler

I think the important thing to remember is that the assignment in Python
is a alias maker and not a copy maker. In languages like C, Fortran,
pascal, the assignment makes a copy from what is on the righthand and
stores that in the variable on the lefthand. In languages like Lisp,
Smalltalk and Python, the assignment essentially makes the lefthand
an alias for the righthand.

Yes, I think I got it now :)

It seems that, in essence, Bruno is right in that Python doesn't really
have variables. Everything that seems variable doesn't really change; what
changes is that an element of what seems to change gets rebound. Which in
itself is a rebinding process of a dictionary... I have yet to go there and
see whether anything at all changes :)

Gerhard
 
A

Antoon Pardon

Yes, I think I got it now :)

It seems that, in essence, Bruno is right in that Python doesn't really
have variables. Everything that seems variable doesn't really change; what
changes is that an element of what seems to change gets rebound.

Aren't you looking too much at implementation details now?

The difference between an alias assignment and a storage assigment
is for instance totaly irrelevant for immutable objects/values like numbers.

On a language level you can't distinghuish between immutable types
where the implementation uses storage assignment or alias assignment
and a number of language implementation do use different implementation
for different types because of optimisation considerations.

AFAIU, one can also build a C++ class hierarchy that with some small
limitations in used operators, would have semantics very similar to
Python. Would you argue that those using such a C++ class hierarchy would
no longer be using variables in C++?
 
G

Gerhard Fiedler

Aren't you looking too much at implementation details now?

Possibly, but at this point I'm still trying to understand how Python does
these things, and what the useful abstraction level is for me. I also still
have very little experience how I'll put the things we've been discussing
here into (Python) practice. While not new to programming, I'm new to
Python.
AFAIU, one can also build a C++ class hierarchy that with some small
limitations in used operators, would have semantics very similar to
Python. Would you argue that those using such a C++ class hierarchy would
no longer be using variables in C++?

Probably not. But for me it's mostly about useful terminology, not
necessarily "correct" terminology. In order to talk about correct
terminology, we'd have to use a common definition of "variable". This is a
term so widely used that I'm not sure there is a useful single definition
of it; do you know one?

In any case, the following doesn't seem to be implementation detail (and
rather a part of the language), but it's not really understandable with a
C++ concept of "variable":
3368140

You don't expect the "identity" of the variable b to change with a simple
assignment from a C/C++ point of view. You also don't expect the "identity"
of a and b to be the same after assigning one to the other. You can create
C++ classes that behave like that (you can implement Python in C++ :), but
that doesn't mean that you expect C++ language constructs to behave like
that.

Gerhard
 
A

Antoon Pardon

Possibly, but at this point I'm still trying to understand how Python does
these things, and what the useful abstraction level is for me. I also still
have very little experience how I'll put the things we've been discussing
here into (Python) practice. While not new to programming, I'm new to
Python.


Probably not. But for me it's mostly about useful terminology, not
necessarily "correct" terminology. In order to talk about correct
terminology, we'd have to use a common definition of "variable". This is a
term so widely used that I'm not sure there is a useful single definition
of it; do you know one?

A name in a scope to which is attached some value/object. Now whether
this attachment is in the form of storage or binding is IMO not
that important.
In any case, the following doesn't seem to be implementation detail (and
rather a part of the language), but it's not really understandable with a
C++ concept of "variable":

3368140

You don't expect the "identity" of the variable b to change with a simple
assignment from a C/C++ point of view.

That depends on what you call the identity. If I had to translate this
into C++ it would be something like:

int *a, *b;

a = MakeInt(3);
b = a;
b = MakeInt(4);

AFAIU, you can wrap these int pointers into some kind of class, so that
they behave as you would expect integers to behave. The id(a) would just
return a, the address of where the integer is stored.

Now whether this is helpfull or not for you in understanding the python
behaviour, I don't know. So if you think this is mixing to many things
I'll drop it.
You also don't expect the "identity"
of a and b to be the same after assigning one to the other. You can create
C++ classes that behave like that (you can implement Python in C++ :),

I'm sorry but IMO you there is no connection between those two.
C doesn't have classes, yet you can still implement Python in C.
but
that doesn't mean that you expect C++ language constructs to behave like
that.

If you have implemented it with that purpose, you do.
 
G

Gerhard Fiedler

[...] we'd have to use a common definition of "variable". This is a term
so widely used that I'm not sure there is a useful single definition of
it; do you know one?

A name in a scope to which is attached some value/object. Now whether
this attachment is in the form of storage or binding is IMO not
that important.

IMO this is not a useful definition of "variable", as it also includes what
some languages would call a "constant". This definition even includes
preprocessor macros. Once you try to come up with a definition that does
not include these, it probably gets trickier.

That depends on what you call the identity. If I had to translate this
into C++ it would be something like:

int *a, *b;

a = MakeInt(3);
b = a;
b = MakeInt(4);

Yup. But in C/C++ speak, it's more common to call a and b "pointers" rather
than "variables". Of course they are also sometimes called "pointer
variables", but not usually "variables". It's of course not technically
wrong to call the variables, but it's probably rare. And for a reason.

If you have implemented it with that purpose, you do.

I'm not sure an implementation of C++ that behaves like Python when
handling ints is still C++.


I'm not sure where you're trying to go. I think that most people (and even
Bruno, who argued this issue most strongly) call Python variables
"variables" every now and then, or maybe even usually. But it was helpful
for me to see the difference between Python variables and, say, C
variables. I think this has been a useful discussion in this respect. There
is a difference, and it is important (IMO).

Whether Python variables are in fact "variables" probably depends mostly on
your definition of "variable", and that's IMO a tough one -- a definition
of "variable" that includes all those language elements that various
languages call "variables", and nothing else (that's the tough part).
Whether that definition exists, and whether it includes Python "variables",
remains to be seen :)

Gerhard
 
H

H J van Rooyen

8<---------------------------------

| I'm not sure where you're trying to go. I think that most people (and even
| Bruno, who argued this issue most strongly) call Python variables
| "variables" every now and then, or maybe even usually. But it was helpful
| for me to see the difference between Python variables and, say, C
| variables. I think this has been a useful discussion in this respect. There
| is a difference, and it is important (IMO).
|
| Whether Python variables are in fact "variables" probably depends mostly on
| your definition of "variable", and that's IMO a tough one -- a definition
| of "variable" that includes all those language elements that various
| languages call "variables", and nothing else (that's the tough part).
| Whether that definition exists, and whether it includes Python "variables",
| remains to be seen :)

I am not one for formal definitions but I think something like this:

if s is a python string containing "hello world "
and I can write :

s = s + "some extra stuff"

then for me s is a variable - the fact that in the python implementation there
are two things, namely the original hello world string and the new longer one is
kind of irrelevant - if I try to print s I will get the new longer string, so
from where I stand s is a variable - it has changed over time from having one
"value" to another one...
and that is about the simplest definition you can get - its a symbolic reference
to something that can change over time - and in python it seems to me that every
name is a variable, cos you can tie the name to very different things at
different times:
s = "hello world"
print s hello world
s = s + " some more stuff"
print s hello world some more stuff
s = [1,2,3,4,5,6,7,8,9,0]
print s [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
def foo():
print "banana"

s is surely a variable - there is nothing constant over time about it, and from
this point of view its very "mutable" indeed - and what is more - in every case,
after the assignment, unless you have stored a reference with a different name
to them, the old values look from a programmer's point of view as if they have
been "overwritten" - you can't use anything about s to get at them again...

Now there's a thought - an optional slice notation that slices s over time,
so that s{0} is the current s, and s{-1} the previous one, and so on, with
the default being s[{0}] the {0} being optional....

This should be relatively easy to implement at the point of re binding the name
by replacing the pointer (or whatever) to the object with a stack of them. I
think you could only do it in python, but I may be wrong...

Another world first for python? - (TIC)

"Look mommy! - I only use one variable name! "

- Hendrik
 
B

Bruno Desthuilliers

Antoon said:
Aren't you looking too much at implementation details now?

The difference between an alias assignment and a storage assigment
is for instance totaly irrelevant for immutable objects/values like numbers.

# Python
a = 42
b = a
del a

# C
int *a, *b;
a = malloc(sizeof *a);
*a = 42;
b = a;
free(a);


I wouldn't say it's "totally" irrelevant.
 
A

Antoon Pardon

[...] we'd have to use a common definition of "variable". This is a term
so widely used that I'm not sure there is a useful single definition of
it; do you know one?

A name in a scope to which is attached some value/object. Now whether
this attachment is in the form of storage or binding is IMO not
that important.

IMO this is not a useful definition of "variable", as it also includes what
some languages would call a "constant". This definition even includes
preprocessor macros. Once you try to come up with a definition that does
not include these, it probably gets trickier.

Sure it is usefull. It may be not 100% formally correct, but often
things that are not 100% formally correct can be better in bringing
an idea accross.

That depends on what you call the identity. If I had to translate this
into C++ it would be something like:

int *a, *b;

a = MakeInt(3);
b = a;
b = MakeInt(4);

Yup. But in C/C++ speak, it's more common to call a and b "pointers" rather
than "variables".

Well in a case like:

int a, b;

You may call a and b "ints" rather than variables, that doesn't stop
them from being variables.
Of course they are also sometimes called "pointer
variables", but not usually "variables". It's of course not technically
wrong to call the variables, but it's probably rare. And for a reason.

Well I don't know about who you talk with, but when I was still using
C and other like languages on a daily basis me and my collegues had
no problem using the word variable, just because the type of the
variable happened to a pointer. AFAIK, the C language reference
doesn't make an exception for calling something a variable, based
on the type (pointer or not) of the variable.
Whether Python variables are in fact "variables" probably depends mostly on
your definition of "variable", and that's IMO a tough one -- a definition
of "variable" that includes all those language elements that various
languages call "variables", and nothing else (that's the tough part).
Whether that definition exists, and whether it includes Python "variables",
remains to be seen :)

Since Python variables seem to behave essentially the same way as
Lisp and Smalltalk variables and as far as I know "variable" is
the accepted term in those languages for what we are talking about,
I don't see how you can have a definition that includes those
languages but will not include python.
 
B

Bruno Desthuilliers

Antoon Pardon wrote:
(snip)
Sure it is usefull. It may be not 100% formally correct, but often
things that are not 100% formally correct can be better in bringing
an idea accross.

hear hear...

And yet you still fail to understand why I claimed Python didn't have
variables ? Talk about stubborness :(
 
D

danielx

Gerhard said:
Possibly, but at this point I'm still trying to understand how Python does
these things, and what the useful abstraction level is for me. I also still
have very little experience how I'll put the things we've been discussing

Sorry I've been away from this sub-thread for a while (even though I
kinda started it :p). Yes, I'm also wondering what difference this big
huge argument makes on how I logically follow Python.

Personally, I find this metaphor in "Head First Java" from O'Reilly
Press really helpful for both Python and Java. Before anyone sends me a
letter bomb that says "Python != Java", let me say this: have phun :p.

Anyway, the metaphor goes something like this: variables (for objects,
not primitives) are like cups (just wait, it gets better). You can put
a remote control IN a cup. The remote control controls a "real" object
on the heap (ie, the data for the object is there).

Unfortunately, some of the effect of the metaphor is lost because I
cannot reporduce the very nice illustrations which came in the book :p.

Other than the fact that you declare variables in Java (going down
another letter-bomb-laden slippery slope), which means they stick
around even when they have no "remote controls", I pretty much think of
Python variables the same way: each variable LOGICALLY contains a
reference (ie, without regard to what the mechanics are) to some
amorphous glob of data, sitting on the heap. Therefore, when I do an
assignment, I am simply replacing the reference my variable is holding.
According to the metaphor, we are replacing the remote control our cup
is holding.

If an object is no longer visible (because all the references have
disappeared), then it should get garbage collected eventually. But
until the magical garbage-collecting angle of death makes is way
through the heap, our orphaned objects are PHYSICALLY still there until
they are forcefully evicted from memory. Logically, however, they were
gone as soon as we lost sight of them.

Java aside, My question is this: how will using this metaphor break the
way I logically follow Python?
here into (Python) practice. While not new to programming, I'm new to
Python.


Probably not. But for me it's mostly about useful terminology, not
necessarily "correct" terminology. In order to talk about correct
terminology, we'd have to use a common definition of "variable". This is a
term so widely used that I'm not sure there is a useful single definition
of it; do you know one?

This is another thing I was thinking the entire time I was reading this
argument, but I didn't want someone to answer me in a condescending
tone on what exactly a variable IS. I guess I should attribute that
quote to Bill Clinton :p.
In any case, the following doesn't seem to be implementation detail (and
rather a part of the language), but it's not really understandable with a
C++ concept of "variable":

3368140

You don't expect the "identity" of the variable b to change with a simple
assignment from a C/C++ point of view. You also don't expect the "identity"
of a and b to be the same after assigning one to the other. You can create
C++ classes that behave like that (you can implement Python in C++ :), but
that doesn't mean that you expect C++ language constructs to behave like
that.

I'm really not comfortable with C, but I disagree. What would you say
about this program:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define tf(bool) (bool) ? "true" : "false"

const char * greeting = "hello world";

int main() {
/* These mallocs don't really need to be hear for me to make my
point, because as far as I know, what they return is garbage
values anyway :p. I just put them there so my pointers are
pointing to "real objects".*/
char * string = (char *) malloc(sizeof(char)*100);
char * letterBomb = (char *) malloc(sizeof(char)*100);

strcpy(string, greeting);
strcpy(letterBomb, greeting);

printf("are we equal? %s\n", tf(strcmp(string, letterBomb) == 0));
printf("are we IDENTICAL? %s\n", tf(string == letterBomb));

printf("sabotage...\n");
letterBomb = string;
printf("are we identical NOW? %s\n", tf(string==letterBomb));
}
 
A

Antoon Pardon

Antoon Pardon wrote:
(snip)

hear hear...

And yet you still fail to understand why I claimed Python didn't have
variables ? Talk about stubborness :(

I don't think it is usefull to claim Python has no variables.

Smalltalk variables behave essentially the same as python
variables and AFAIK never has the term 'variable' been
seen there as an obstacle for understanding how smalltalk
works.

Python objects/classes don't behave exactly the same as
objects/classes in some other languages, are you going to claim
that python has no objects/classes when you want to explain
these difference? What other terminology are you prepared to
throw away because things behave somewhat differently in Python
than they do in some other languages?

IMO you are the one who seem to want 100% formally correctness,
because you wanted to throw away a term because the entity
refered to by it, didn't behave exactly the same as it did
in an other language.
 
A

Antoon Pardon

Sorry I've been away from this sub-thread for a while (even though I
kinda started it :p). Yes, I'm also wondering what difference this big
huge argument makes on how I logically follow Python.

Personally, I find this metaphor in "Head First Java" from O'Reilly
Press really helpful for both Python and Java. Before anyone sends me a
letter bomb that says "Python != Java", let me say this: have phun :p.

Anyway, the metaphor goes something like this: variables (for objects,
not primitives) are like cups (just wait, it gets better). You can put
a remote control IN a cup. The remote control controls a "real" object
on the heap (ie, the data for the object is there).

Unfortunately, some of the effect of the metaphor is lost because I
cannot reporduce the very nice illustrations which came in the book :p.

Other than the fact that you declare variables in Java (going down
another letter-bomb-laden slippery slope), which means they stick
around even when they have no "remote controls", I pretty much think of
Python variables the same way: each variable LOGICALLY contains a
reference (ie, without regard to what the mechanics are) to some
amorphous glob of data, sitting on the heap. Therefore, when I do an
assignment, I am simply replacing the reference my variable is holding.
According to the metaphor, we are replacing the remote control our cup
is holding.

If an object is no longer visible (because all the references have
disappeared), then it should get garbage collected eventually. But
until the magical garbage-collecting angle of death makes is way
through the heap, our orphaned objects are PHYSICALLY still there until
they are forcefully evicted from memory. Logically, however, they were
gone as soon as we lost sight of them.

Java aside, My question is this: how will using this metaphor break the
way I logically follow Python?

I don't think it will cause you problems. The confusion from explaining
Python variables in terms of C-like references comes from the fact that
in Python both assignment and argument passing are reference passings.

In code like the following:

def foo(x):
x = x + 1

a = 0
f(a)
print a

A number of people expect to see 1 printed. They remember that x will
be a reference of a and so expect a to be incremented by 1 after the
call. They forget that the assigment to x will cause x to refer to
a different integer and not cause it to refer to the same "object"
whose value is increased.

An other problem is that people don't realise that an assignment
to a simple identifier in a function, has a declarative effect.
So (unless the identifier was declared global) from the moment
there is some line like: ident = ... in a function, all occurences
of ident in that function will refer to the local variable.

So this works:

def foo():
b = a

a = 1
foo()

This doesn't:

def foo():
b = a
a = 2 * b + 1

a = 1
foo()

Even this doesn't:

def foo():
if False:
a = 1
else:
b = a

a = 1
foo()

Yet seems to work (which I think is an error in the optimisation;
replacing 0 by [], () or None shouldn't make a difference but
it no longer works in those cases):

def foo():
if 0:
a = 1
else:
b = a

a = 1
foo()
 
G

Gerhard Fiedler

You don't expect the "identity" of the variable b to change with a
simple assignment from a C/C++ point of view. You also don't expect the
"identity" of a and b to be the same after assigning one to the other.
You can create C++ classes that behave like that (you can implement
Python in C++ :), but that doesn't mean that you expect C++ language
constructs to behave like that.

I'm really not comfortable with C, but I disagree. What would you say
about this program: [...]

"Identity of a variable" is probably even less defined than "variable" :)

What I meant is that in a C/C++ context, I'd fuzzily think about identity
of a variable as its location, the memory address. In this sense, you
change the identity of the content of the pointers, but not the identity of
the pointer variable itself.

After the line "letterBomb = string;", both letterBomb and string still
have each their own "identity" (as in memory address). You copied the
content; which is in this case the address that was stored in string. It's
that level that you never get to in Python (normal Python programming, at
least, I think :).

I think it's probably pretty moot to compare the low level C concept of
variables with the higher level concept of variables that most scripting
languages have. There's a lot of built-in functionality behind the scenes
that C lacks. It of course can be simulated in C with certain assumptions,
but that's not the point.

There's maybe a point in comparing Python variables to C pointers. But it
lacks in the respect that a C programmer is used to modify memory locations
through pointers. A Python programmer isn't used to modify memory locations
in the first place, and simple objects don't get modified at all. There's
no Python equivalent to "int*p=345; *p++;". (There's no need for that in
Python; I'm not saying this shows a superiority of C. It just shows a
different concept of what "variable" means.)

For me, the point of this discussion was that it makes sense to look at it
/differently/. Once you've done that, there's no problem in continuing to
use the (vaguely defined) term "variable".

I admit that for me it was a surprise when I learned that simple numbers
are immutable objects, and I'm sure this wasn't the last time I'll think a
bit about the ramifications of this.

Gerhard
 
D

Duncan Booth

Antoon said:
Even this doesn't:

def foo():
if False:
a = 1
else:
b = a

a = 1
foo()

Yet seems to work (which I think is an error in the optimisation;

What definition of 'seems to work' are you using? It throws an
UnboundLocalError exception so you'll know pretty quickly that something is
wrong.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,190
Members
46,740
Latest member
AdolphBig6

Latest Threads

Top