Re: why cannot assign to function call

2009-03-14 Thread Aahz
In article mailman.952.1235850376.11746.python-l...@python.org,
 rdmur...@bitdance.com wrote:

I think this is the key point.  I am an experienced Python programmer,
and I had to think long and hard about what you were saying, Mark, in
order to understand how it applied to Python.  I think this means that
your model and/or your level of abstraction is not natural when trying
to understand Python programs, and I think I may have figured out why.

Good job!  I'll just add one little bit to your excellent rebuttal:

Assignment in Python changes a mapping (mutates a namespace object). In
this case the mapping being changed is the local function's namespace
mapping.  We can't affect the caller's namespace mapping, because (in
this function) we don't have access to the caller's namespace object.
So I would diagram it like this:

 y (in global env.)  - 'virgin'

 x (in function 'test')   'clobbered'

Although you later make clear that this model works well with lists, too,
I personally find it easier to separate the concept of name (which is
strictly the set of legal Python identifiers) with the more general
concept of target.  Consider this:

 L = [1, 2, 3]
 L[1:1] = ['foo', 'bar']

What do you call ``L[1:1]``?  I call that a target (and in fact, so do
the Python docs).
-- 
Aahz (a...@pythoncraft.com)   * http://www.pythoncraft.com/

All problems in computer science can be solved by another level of 
indirection.  --Butler Lampson
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-03-14 Thread Terry Reedy

Aahz wrote:

In article mailman.952.1235850376.11746.python-l...@python.org,
 rdmur...@bitdance.com wrote:

I think this is the key point.  I am an experienced Python programmer,
and I had to think long and hard about what you were saying, Mark, in
order to understand how it applied to Python.  I think this means that
your model and/or your level of abstraction is not natural when trying
to understand Python programs, and I think I may have figured out why.


Good job!  I'll just add one little bit to your excellent rebuttal:


Assignment in Python changes a mapping (mutates a namespace object). In
this case the mapping being changed is the local function's namespace
mapping.  We can't affect the caller's namespace mapping, because (in
this function) we don't have access to the caller's namespace object.
So I would diagram it like this:

y (in global env.)  - 'virgin'

x (in function 'test')   'clobbered'


Although you later make clear that this model works well with lists, too,
I personally find it easier to separate the concept of name (which is
strictly the set of legal Python identifiers) with the more general
concept of target.  Consider this:


L = [1, 2, 3]
L[1:1] = ['foo', 'bar']


What do you call ``L[1:1]``?


I call that a collection slot.


 I call that a target (and in fact, so do the Python docs).


Targets encompass both names and slots.

--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-02-28 Thread Mark Wooding
Ethan Furman et...@stoneleaf.us writes:

 Mark Wooding wrote:
 Here's what I think is the defining property of pass-by-value [...]:

   The callee's parameters are /new variables/, initialized /as if by
   assignment/ from the values of caller's argument expressions.

 My soundbite definition for pass-by-reference is this:

   The callee's parameters are merely /new names/ for the caller's
   argument variables -- as far as that makes sense.

 Greetings, Mark!

You posted to the whole group -- probably using a wide-reply option
while reading the mailing list.  Still, I'll give an answer here in
order to help any other readers of the list or newsgroup.  However, as
far as I'm concerned, this discussion is basically at an end and I'm not
really interested in starting it up all over again.  To that end, I've
set followups to `poster'.  I shall continue reply to private email
which seems interested in a sensible discussion.

 I was hoping you might be able to clarify those last two sound bites
 for me -- I think I understand what you are saying, but I'm confused
 about how they relate to Python...

 Specifically, how is a new name (pbr) different, in Python, from a new
 name initialized as if by assignment (pbv)?  It seems to me than you
 end up with the same thing in either case (in Python, at least),
 making the distinction non-existent.

You've missed a level of indirection.  In particular, `names' aren't
things that you initialize.  They're things that you /bind/ to
variables.  The crucial difference is that, in pass-by-value, new
variables are created as an intrinsic part of the process, whereas in
pass-by-reference, new variables are not (usually) created, and instead
the formal parameter names are bound to the caller's pre-existing
argument variables.

It's worth noting that I use the terms `name' and `binding' in different
ways from most of the Python community.  This is unfortunate.  The
discrepancy is actually because the Python meanings of these words are
not the same as the meanings in the wider computer science and
mathematical communities.  For example, many Python users seem to use
`binding' to mean `assignment', which is a shame because it leaves the
concept that is usually called `binding' without a name.  So I'll stick
with the wider meanings.

A while ago, I posted an essay -- to this group -- which may help
explain the concepts:

Message-ID: 8763k14nc6.fsf@metalzone.distorted.org.uk
http://groups.google.com/group/comp.lang.python/msg/f6f1a321f819d02b

On with the question.

 def func(bar):
 bar.pop()

 Pass-by-reference:
   foo = ['Ethan','Furman']
   func(foo)   # bar = foo

 Pass-by-value:
   foo = ['Python','Rocks!']
   func(foo)   # bar is new name for foo
   # is this any different from above?

 If I have this right, in both cases foo will be reduced to a
 single-item list after func.  

You're correct.  So: we can conclude that the above test is not
sufficient to distinguish the two cases.

 Any further explanation you care to provide will be greatly
 appreciated!

This test is sufficient to distinguish:

def test(x):
  x = 'clobbered'

y = 'virgin'
test(y)
print y

If it prints `virgin' then you have call-by-value.  If it prints
`clobbered' then you have call-by-reference.

Let's examine the two cases, as I did in the essay I cited above.  I'll
do call-by-value first.  First, we define a function `test'.  Then, we
initialize `y'.  It's worth examining this process in detail.  The name
`y' is initially unbound. so it is implicitly bound to a fresh
variable.  Then, (a reference to) the string object 'virgin' is stored
in this variable.  We can show this diagrammatically as follows.

y (in global env.)    [VAR]  --- 'virgin'

(In the diagrams, === denotes a binding relationship, between names and
variables; and --- denotes a reference relationship, between variables
and values.)

Next, we call the `test' function.  Call-by-value says that we must
evaluate the argument expressions.  There's only one: `x'.  The value of
a name is obtained by (a) finding which variable is bound to the name,
and (b) extracting the value from this variable.  Well, the variable is
the one we just bound, and the value stored is (the reference to) the
string 'virgin'.  So the result of evaluating the argument expressions
is simply (the reference to) that string.

The function has one parameter, `y'.  A new environment is constructed
by extending the global environment.  In this new environment, the name
`y' is bound to a fresh variable -- distinct from all others, and
especially from the variable bound to `x' -- and in that variable we
store the value of the corresponding argument expression.  Result: the
function body is executed in an environment which is like the global
environment except that `y' is bound to a fresh variable containing
'virgin'.

y (in global env.) 

Re: why cannot assign to function call

2009-02-28 Thread rdmurray
Mark Wooding m...@distorted.org.uk wrote:
 Ethan Furman et...@stoneleaf.us writes:
 
  Mark Wooding wrote:
  Here's what I think is the defining property of pass-by-value [...]:
 
The callee's parameters are /new variables/, initialized /as if by
assignment/ from the values of caller's argument expressions.
 
  My soundbite definition for pass-by-reference is this:
 
The callee's parameters are merely /new names/ for the caller's
argument variables -- as far as that makes sense.
 
  Greetings, Mark!
 
 You posted to the whole group -- probably using a wide-reply option
 while reading the mailing list.  Still, I'll give an answer here in
 order to help any other readers of the list or newsgroup.  However, as
 far as I'm concerned, this discussion is basically at an end and I'm not
 really interested in starting it up all over again.  To that end, I've
 set followups to `poster'.  I shall continue reply to private email
 which seems interested in a sensible discussion.

I just popped in to this thread, and read the whole thing in a marathon
session (why, I'm not quite sure, but somehow I found it interesting :).
I'm going to follow up here at the risk of annoying Mark, because I
think there may be a way to reconcile the language in a way that is
helpful in explaining things to Python beginners.

  I was hoping you might be able to clarify those last two sound bites
  for me -- I think I understand what you are saying, but I'm confused
  about how they relate to Python...

I think this is the key point.  I am an experienced Python programmer,
and I had to think long and hard about what you were saying, Mark, in
order to understand how it applied to Python.  I think this means that
your model and/or your level of abstraction is not natural when trying
to understand Python programs, and I think I may have figured out why.

  Specifically, how is a new name (pbr) different, in Python, from a new
  name initialized as if by assignment (pbv)?  It seems to me than you
  end up with the same thing in either case (in Python, at least),
  making the distinction non-existent.
 
 You've missed a level of indirection.  In particular, `names' aren't
 things that you initialize.  They're things that you /bind/ to
 variables.  The crucial difference is that, in pass-by-value, new
 variables are created as an intrinsic part of the process, whereas in
 pass-by-reference, new variables are not (usually) created, and instead
 the formal parameter names are bound to the caller's pre-existing
 argument variables.

I think that the reason Ethan missed that level of indirection is that
Python hides that level of indirection from the programmer.  And I think
that this is where the conversation between you and Steven got hung
up, Mark.  You are firmly grounded in how languages work in general,
so your conceptual model naturally includes details that Steven's
conceptual model can ignore, because he's dealing only with the model
used by Python.  He can (and wants to!) ignore the level of indirection
that Python doesn't even give him access to.

In short, there is a reason why you almost never hear the word 'variable'
from an experienced Python programmer when talking about the Python model.
That level detail is abstracted into something else by the Python
conceptual model: it becomes a namespace mapping names to objects.

 It's worth noting that I use the terms `name' and `binding' in different
 ways from most of the Python community.  This is unfortunate.  The
 discrepancy is actually because the Python meanings of these words are
 not the same as the meanings in the wider computer science and
 mathematical communities.  For example, many Python users seem to use
 `binding' to mean `assignment', which is a shame because it leaves the
 concept that is usually called `binding' without a name.  So I'll stick
 with the wider meanings.

It seems to me from reading the thread that everyone is actually in
pretty good agreement that 'name' is the symbol one types in the
program source to denote...something.  It's the something where things
get tricky.  So let's leave name itself alone.

But let's replace 'assignment' and 'binding' with the concept that is
more natural to Python's model, that of a mapping.  A namespace maps
names to objects.  If I'm understanding you correctly, Mark, in your
model what I'm calling a namespace is the set of variable bindings in a
particular environment.  Because Python does not allow the programmer
to actually rebind a variable (Python handles the association between
name and variable completely behind the scenes), Python programmers
naturally skip past that name-to-variable binding step, and conceptually
think about the name being bound to the _value_ instead. After all,
that's the only thing they can change.  This may be unfortunate from
a precisionist viewpoint, but it is both natural and, IMO, inevitable,
because it makes thinking about Python programs more efficient.

 A while ago, I 

Re: why cannot assign to function call

2009-02-28 Thread Tim Roberts
Ethan Furman et...@stoneleaf.us wrote:

Specifically, how is a new name (pbr) different, in Python, from a new 
name initialized as if by assignment (pbv)?  It seems to me than you end 
up with the same thing in either case (in Python, at least), making the 
distinction non-existent.

def func(bar):
 bar.pop()

Pass-by-reference:
   foo = ['Ethan','Furman']
   func(foo)   # bar = foo

The problem here, in my view, is the terminology.  It is true that, inside
the function func, bar will refer to the same list that foo refers
to.  However, it is inaccurate to think of this list as foo.  There
exists a list -- an anonymous list in object space -- and while func is
executing, there are two names bound to that list.  So, the bar.pop()
instruction changes that anonymous list, you'll see those changes if you
inspect foo after the call.

Pass-by-value:
   foo = ['Python','Rocks!']
   func(foo)   # bar is new name for foo
   # is this any different from above?

Yes, it's different.  If Python really had pass by value, that function
call would pass a COPY of the list.  The function would receive the list's
value, not the list itself.

If I have this right, in both cases foo will be reduced to a single-item 
list after func.  Any further explanation you care to provide will be 
greatly appreciated!

Nope.  Under pass-by-value semantics, func could dance on the list to its
heart's content, and foo would not be changed.
-- 
Tim Roberts, t...@probo.com
Providenza  Boekelheide, Inc.
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-02-27 Thread Ethan Furman

Mark Wooding wrote:

Steven D'Aprano ste...@remove.this.cybersource.com.au wrote:


On the one hand, some people (me and possibly rurpy) consider this is 
pass-by-foo to be a statement about behaviour directly visible to the 
programmer. We have a set of behavioral traits in mind, and if a language 
exhibits those behaviours, then it is clearly and obviously pass-by-foo 
no matter how that behaviour is implemented. I'll call these the 
behaviorists.


Here's the problem.  I think I'm in that camp too!

I'm going to move away from the formal semantics stuff and try a
different tack.  Here's what I think is the defining property of
pass-by-value (distilled from the formal approach I described earlier,
but shorn of the symbolism):

  The callee's parameters are /new variables/, initialized /as if by
  assignment/ from the values of caller's argument expressions.



My soundbite definition for pass-by-reference is this:

  The callee's parameters are merely /new names/ for the caller's
  argument variables -- as far as that makes sense.

There's a caveat there for argument expressions which don't correspond
directly to variables -- and I've glossed over the issue of lvalue
expressions which designate locations and all of that. 


Greetings, Mark!

A little background on myself, hopefully making my soon-to-follow 
question less idiotic.


I've been in the PC world for 20+ years now, and dabbled with 
programming through much of that time.  I've written small utilities in 
Assembly (x86) and CL (AS/400), I just recently wrote a dbf module for 
python, and I've studied (in and out of the classroom) C, Fortran, 
Pascal, Java, Perl, Php, and Basic.


While I have had some formal training, my degree is in Business (long 
story -- I would rather have done CS), and much of your explanation in 
previous posts was way over my head.


I am in complete agreement with Steven's description of the behaviorist 
point of view for pass-by-value and pass-by-reference, and if asked I 
would say Python is pass-by-object.  I offer this so you know where I'm 
coming from, not from any hostile motive.


I was hoping you might be able to clarify those last two sound bites for 
me -- I think I understand what you are saying, but I'm confused about 
how they relate to Python...


Specifically, how is a new name (pbr) different, in Python, from a new 
name initialized as if by assignment (pbv)?  It seems to me than you end 
up with the same thing in either case (in Python, at least), making the 
distinction non-existent.


def func(bar):
bar.pop()

Pass-by-reference:
  foo = ['Ethan','Furman']
  func(foo) # bar = foo

Pass-by-value:
  foo = ['Python','Rocks!']
  func(foo) # bar is new name for foo
# is this any different from above?

If I have this right, in both cases foo will be reduced to a single-item 
list after func.  Any further explanation you care to provide will be 
greatly appreciated!


~Ethan~
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-02-27 Thread Rhodri James
On Fri, 27 Feb 2009 23:55:43 -, Ethan Furman et...@stoneleaf.us  
wrote:


I'm not Mark, but you did post to the whole group!

[snippety snip]

Specifically, how is a new name (pbr) different, in Python, from a new  
name initialized as if by assignment (pbv)?  It seems to me than you end  
up with the same thing in either case (in Python, at least), making the  
distinction non-existent.


def func(bar):
 bar.pop()

Pass-by-reference:
   foo = ['Ethan','Furman']
   func(foo)# bar = foo

Pass-by-value:
   foo = ['Python','Rocks!']
   func(foo)# bar is new name for foo


With true pass-by-value, this comment is not true.  Bar would be a copy
of foo, not a new name.  What happens to bar is then not reflected in
foo (depending on how deep the copy is), which is the objective of
pass-by-value.

--
Rhodri James *-* Wildebeeste Herder to the Masses
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-15 Thread Lie
On Jan 5, 9:03 am, Derek Martin c...@pizzashack.org wrote:
 On Sat, Jan 03, 2009 at 10:15:51AM +, Marc 'BlackJack' Rintsch wrote:
  On Fri, 02 Jan 2009 04:39:15 -0600, Derek Martin wrote:

   On Tue, Dec 30, 2008 at 02:21:29PM +, John O'Hagan wrote:
   What the Python community often overlooks, when this discussion again
   rears its ugly head (as it seems to every other hour or so), is that its
   assignment model is BIZARRE, as in it's conceptually different from
   virtually all other languages substantially taught in undergraduate
   computer science programs.

  What's the difference between Python and Java or C# here!?  Or are they
  also BIZARRE!?

 I am happily ignorant of C#.  As for Java, take the following code:

   a = 6;
   a = 5;

 In Python, when you execute the equivalent code, it causes two
 different objects to spring into existence, the first of which may be
 cleaned up by the GC (except that since we're using small integers,
 that's not likely to happen).  Unless I'm misinformed (which is very
 possible, my experience with Java has been extremely limited) in Java
 that's not the case...  the storage is allocated to the name a when
 you execute its declaration, and the *same storage* is reused upon
 subsequent assignment.

 That behaves exactly like named bins.

   And for that matter, it's pretty unintuitive generally.

  Names and objects are quite natural IMHO.  There are many real world
  objects which we attach one or more names to, or refer to in sequences
  like please give me the third book on that shelve (``shelve[2]``).

 Indeed, but the way we assign names to them does not behave as it does
 in Python.  Nor does Python's assignment work like it does in algebra,
 or anywhere else the Python student is particularly likely to have
 seen variable assignment before encountering it in Python.  Let's
 define intuitive, shall we?  From dictionary.com (choosing the
 definition which most easily makes my point):

   intuitive: adj.  capable of being perceived or known by intuition.

 I'm going to go out on a limb and assert that there's NO POSSIBLE WAY
 a student could intuit Python's variable assignment behavior, having
 never been exposed to that same behavior prior.  It needs to be
 taught.

Which limb would you like to go with?

   That is, in what I'll call normal computer languages, a variable name
   is thought of as the address of a bin where some data is stored, and the
   name is inexorably tied to that bin.

  You just call that normal or intuitive because that's what you
  learned first.

 In a sense, yes... but isn't that what intuition really is?  You can
 figure something out whithout being told how it works...  That's
 either because it's immediately obvious from observing it, or it
 behaves like something you've seen before.  That is what intitive is.

No. You've just said it yourself, something is intuitive if it
behaves like something you've seen before. People have different
experience, people deeply involved in mathematics would see named
bin is the obvious thing to go, however commoners (including
mathematician) will have different say: Derek is the name of a human
object instead of Derek is a specific collection of atoms that
resembles human.

This is also why python community tend to avoid the use of variable,
because python's name doesn't behave like variables in mathematics, it
behaves like name. (heck, one would argue that even variable in
programming is not exactly the same as variable in mathematic
either)

  I think the bin model is more complex because you don't just have a
  name and an object but always that indirection of the bin.

 I cheerfully disagree. :)  Named bins is essentially how algebra
 works, and how several generations of computer languages, not to
 mention the actual machine language those generated, behaved, before
 the current crop.  Those interpretations came first, because, much as
 in the evolution of any other science, that was the model which was
 most intuitive or easily explained.

No, it is neither the most intuitive nor easily explained, but indeed
it is the simplest to implement as humans at that time have limited
capability to design chips. In the early days, ease of use is not a
priority, simplicity is.

 But you need not take my word for it.  Simply read the archives and
 see for yourself how much confusion this has caused on this list.
 [Please include the closely related behavior of parameter passing in
 your search.]

The first time I used python, I didn't have any idea how the object
model works, and I don't have experience in similar programming
concept nor was python my first language, yet I have no difficulty in
understanding why things goes like it is. For me, at least, python's
object model is intuitive (do you remember about the limb?).
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-14 Thread Steven D'Aprano
On Tue, 13 Jan 2009 23:06:58 +, Mark Wooding wrote:


 I'm going to move away from the formal semantics stuff and try a
 different tack.  Here's what I think is the defining property of
 pass-by-value (distilled from the formal approach I described earlier,
 but shorn of the symbolism):
 
   The callee's parameters are /new variables/, initialized /as if by
   assignment/ from the values of caller's argument expressions.


Well, that's one way of looking at it, I guess. The problem is that when 
I do this:

x = something  # just an example, not necessarily a string
y = x

Does the line y=x create a new variable? Depends on what you mean by 
variable. If you mean a new name, symbol or whatever, then obviously yes. 

But if you mean a new value, namely the string something, then not 
necessarily. In Pascal (and C?) those bytes are copied, giving two 
independent values which just happen to be equal. In Python, both x and y 
refer to the same string, and I choose the term deliberately. See, I'm 
not *entirely* against the use of referring to references, when 
appropriate. I think we just differ on when we think it's appropriate.

Which I guess brings us back to your earlier assertion (I think it was 
you) that people aren't confused about argument passing, they're confused 
about assignment. 

[...]

 But! (you claim) ...
 
 Python simply can't be pass-by-value, because it doesn't behave like
 pass-by-value in other languages (particularly C and Pascal).
 
 Ah! (say I) but assignment in C and Pascal looks different from the way
 it looks in C

I'm sorry, that confuses me. Assignment in C looks different from the way 
it looks in C? I guess the second C should be Python.

 -- and in exactly the same way that argument passing looks
 different.  And there, I think, I'm going to rest my case.
 
 I'm sorry I took so long to distill these thoughts.  Thank you for
 putting up with my theoretical meanderings on the way.

And thank you for not kill-filing me when tempers were getting short.



-- 
Steven
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-14 Thread Mark Wooding
Steven D'Aprano ste...@remove.this.cybersource.com.au wrote:
  Ah! (say I) but assignment in C and Pascal looks different from the way
  it looks in C
 
 I'm sorry, that confuses me. Assignment in C looks different from the way 
 it looks in C? I guess the second C should be Python.

Yes, you're right.  Stupid mistake on my part.

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-14 Thread Mark Wooding
Aaron Brady castiro...@gmail.com wrote:

 On Jan 13, 5:06 pm, Mark Wooding m...@distorted.org.uk wrote:
 snip
  I'm going to move away from the formal semantics stuff and try a
  different tack.  Here's what I think is the defining property of
  pass-by-value (distilled from the formal approach I described earlier,
  but shorn of the symbolism):
 
The callee's parameters are /new variables/, initialized /as if by
assignment/ from the values of caller's argument expressions.
 
 In other words, the same as assignment in that language.

It's the same as assignment of /values/ to /fresh variables/.  It's
important to specify that argument expressions are fully evaluated, and
that nothing gets overwritten in the process.

So the difference between Python and C is that C copies values during
assignment, but Python doesn't.  Therefore the argument passing works
the same way.

  Because its argument passing works the same way as its assignment.
 
 That would be called pass-by-assignment.  But you've just postponed
 explaining yourself.  Stop delegating and work.

Huh?  I'm really at a loss to know what you want me to do.

I can't help it if people are confused over the phrase `pass-by-value',
beyond trying to explain what it means using clear definitions.  The
`value' part means that argument expressions are /evaluated/ (turned
into values), which forces applicative-order semantics rather than (say)
normal-order.

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-14 Thread Aaron Brady
On Jan 14, 3:51 am, Mark Wooding m...@distorted.org.uk wrote:
 Aaron Brady castiro...@gmail.com wrote:
  On Jan 13, 5:06 pm, Mark Wooding m...@distorted.org.uk wrote:
  snip
   I'm going to move away from the formal semantics stuff and try a
   different tack.  Here's what I think is the defining property of
   pass-by-value (distilled from the formal approach I described earlier,
   but shorn of the symbolism):

     The callee's parameters are /new variables/, initialized /as if by
     assignment/ from the values of caller's argument expressions.

  In other words, the same as assignment in that language.

 It's the same as assignment of /values/ to /fresh variables/.  It's
 important to specify that argument expressions are fully evaluated, and
 that nothing gets overwritten in the process.

 So the difference between Python and C is that C copies values during
 assignment, but Python doesn't.  Therefore the argument passing works
 the same way.

That interferes with Joe's claim that the value of a variable is a
memory address.  I think you'd have better luck sticking with pass-by-
assignment.

A Java reference and a C++ reference are different things, somewhat
regrettably.

   Because its argument passing works the same way as its assignment.

  That would be called pass-by-assignment.  But you've just postponed
  explaining yourself.  Stop delegating and work.

 Huh?  I'm really at a loss to know what you want me to do.

You were remarkably civil about that.  I regretted it as soon as I
sent it.  You keep wanting to say but it's just a reference, it's
just a reference.  But all that does is put more burden on the fellow
that explains what a reference is.  It took me years to grasp
pointers... possibly all the way up until comp. architecture class.
(As such, I find you're shirking.)

 I can't help it if people are confused over the phrase `pass-by-value',
 beyond trying to explain what it means using clear definitions.  The
 `value' part means that argument expressions are /evaluated/ (turned
 into values), which forces applicative-order semantics rather than (say)
 normal-order.

I can't believe it's taken this long, including October's discussion
(name dropping and especially with my dual (not duel, ha!) in
Philosophy /dropping), but I'd finally like to quote the manuals.

An object's identity never changes once it has been created.
The value of some objects can change.
- http://docs.python.org/reference/datamodel.html

Therefore, an object's value is not its identity.  (Its identity is
something other than its value.)  You might get away with 'pass-by-
identity'.

After 'X= [1, 2, 3]', X refers to an object.  You can change two
things: (1) the fact that X refers to that object, (2) that object.

In 'X= None' and 'del X', you change the fact that X refers to that
object.  In 'X[:]= [4, 5, 6]' and 'X.pop()', you change the object.

Explanatory note: It really takes two sentences to say that.  'X
refers to an object.  You can change the object, or change the fact
that X refers to it.'  If you try to say it in one sentence, the
distinction collapses:  'You can change (1) the object that X refers
to, or (2) the object that X refers to.'  Irony!

'X' is a key in a namespace.

namespace[ 'X' ]= [1, 2, 3]
namespace[ 'Y' ]= namespace[ 'X' ]
del namespace[ 'X' ]

No matter how hard you try, if you don't have both of two things,
'namespace' and 'X', you can't change namespace[ 'X' ].

And back to the OP (long since gone, naturally): You can do:
f()[:]= [1, 2, 3]
As well as:
f().replace( [1, 2, 3] )
As well as:
f().contents= [1, 2, 3]

The particular thing s/he wanted isn't one of these.

Lastly, I think it would do you and Joe good to ignore some details,
when thinking about beginners.
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-13 Thread Steven D'Aprano
On Sat, 10 Jan 2009 15:46:35 +, Mark Wooding wrote:

 [Another tome.  I hope this contains sufficient new material to continue
 to be of interest to other readers.]

I found it interesting. I don't know about others. However, at 756 lines 
(including quoting) it was nearly double the size of my previous tome, so 
I think this discussion is clearly not going anyway. I think this 
conversation is reaching it's natural end. Frustration levels are rising. 
I could -- and in fact intended to -- write a point-by-point argument, 
but that would only send the size of this skyrocketing and probably 
nobody would read it. So I'm going to take a different tack in an attempt 
to reduce frustration levels: if I can't convince the other side they're 
wrong, can I at least get them to understand where I'm coming from a 
little better?

As I see it, this conversation is floundering on two radically different 
ideas about what it means to say a language uses pass-by-foo.

On the one hand, some people (me and possibly rurpy) consider this is 
pass-by-foo to be a statement about behaviour directly visible to the 
programmer. We have a set of behavioral traits in mind, and if a language 
exhibits those behaviours, then it is clearly and obviously pass-by-foo 
no matter how that behaviour is implemented. I'll call these the 
behaviorists.

On the other hand, others (I'm going to put Joe and Mark into this group) 
consider pass-by-foo to be a statement about mechanism, or if you 
prefer, implementation. If a compiler does X, then the language is pass-
by-foo, regardless of behaviour. I'll call these the mechanists.

To a behaviorist, Python simply can't be pass-by-value, because it 
doesn't behave like pass-by-value in other languages (particularly C and 
Pascal). The Python community has a tradition of duck-typing: if it 
quacks like a duck and swims like a duck, then it is a duck in every way 
that is important. If it can't swim and doesn't quack, it isn't a duck, 
no matter how much duck DNA is in it. If it flies, that's irrelevant to 
the question, because some ducks fly and some don't.

According to the behaviorist view, what makes an evaluation strategy call-
by-reference is whether or not it exhibits the following three behaviours:

(1) passing a value to a function does not copy the value;

(2) modifications to the value inside the function are visible to the 
caller;

(3) assignments to the value inside the function are visible to the 
caller.

where value means the thing the programmer manipulates symbolically in 
source code. Values are ints, strings, lists and so forth. Pointers or 
references are *only* values if the language allows you to write the 
equivalent of:

ptr = SomeReferenceTo(x)  # like Pascal's ptr := ^x;
x = Dereference(ptr)  # like Pascal's x := ptr^;


According to this viewpoint, Python clearly cannot be pass-by-reference 
because (3) is not true.


Similarly, what makes pass-by-value is:

(1) passing a value to a function makes a copy of the value, where value 
is an entity the programmer can symbolically manipulate in source code 
(lists, ints, floats etc.);

(2) modifications to the value inside the function are not visible to the 
caller;

(3) assignments to the value inside the function are not visible to the 
caller.

According to this viewpoint, Python clearly cannot be pass-by-value 
either because neither (1) nor (2) are true. The underlying mechanism is 
irrelevant.

Mechanists take a different view. A typical argument paraphrased from Joe 
in previous threads is:

Of course Python makes a copy of the value you pass to a function. The 
difference is that the value you pass is a reference.

Mechanists reject the restriction that values only include entities 
manipulated by the programmer. Consequently they're prepared to say that 
values in Python aren't the things which Python programmers symbolically 
manipulate (strings, ints etc.) but are references. Needless to say this 
claim strikes behaviorists as nonsensical and rather incoherent. If the 
value of 2 isn't 2, then value has no meaning. If mechanists see the 
behaviorists as willfully ignorant, the behaviorists see the mechanists 
as being blatantly obfuscatory, introducing irrelevant details and 
ignoring clear examples of the duck quacking.


And these two viewpoints are why this debate never ends, merely goes 
quite for a few weeks or months.



-- 
Steven
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-13 Thread Mark Wooding
Steven D'Aprano ste...@remove.this.cybersource.com.au wrote:

 I found it interesting. 

Well, that's something, at any rate.

 I think this conversation is reaching it's natural end. Frustration
 levels are rising. 

I think you may be right.  That said...

 So I'm going to take a different tack in an attempt to reduce
 frustration levels: if I can't convince the other side they're wrong,
 can I at least get them to understand where I'm coming from a little
 better?

Maybe...

 As I see it, this conversation is floundering on two radically different 
 ideas about what it means to say a language uses pass-by-foo.

You might be right, but I'm unconvinced.

 On the one hand, some people (me and possibly rurpy) consider this is 
 pass-by-foo to be a statement about behaviour directly visible to the 
 programmer. We have a set of behavioral traits in mind, and if a language 
 exhibits those behaviours, then it is clearly and obviously pass-by-foo 
 no matter how that behaviour is implemented. I'll call these the 
 behaviorists.

Here's the problem.  I think I'm in that camp too!

I'm going to move away from the formal semantics stuff and try a
different tack.  Here's what I think is the defining property of
pass-by-value (distilled from the formal approach I described earlier,
but shorn of the symbolism):

  The callee's parameters are /new variables/, initialized /as if by
  assignment/ from the values of caller's argument expressions.

I'd just like to examine that for a bit.  Firstly, let's expand it from
the soundbite: basically what it says is that you should be able to
replace

  function mumble(a, b, c) { stuff in terms of a, b, and c }
  ...
  mumble(1 + 2, xyz, whatever)

with

  ...
  fresh_a = 1 + 2
  fresh_b = xyz
  fresh_c = whatever
  stuff in terms of fresh_a, fresh_b, and fresh_c

with no observable difference (here, fresh_a and so on are a variable
names not appearing in the rest of the program).  So:

  * It captures C's behaviour (at least if you don't count arrays --
let's not open that one again), and Pascal's normal behaviour.
Assigning to the parameters doesn't affect the caller's argument
variables because the parameters are fresh variables.

  * It /doesn't/ capture Fortran's behaviour, or Pascal's `var'
parameters, because obviously assignment to parameters in Fortran
/can/ affect the caller's argument variables

  * It also doesn't capture exotic things like Algol's call by name, and
lazy evaluation, because there's an evaluation step in there.

My soundbite definition for pass-by-reference is this:

  The callee's parameters are merely /new names/ for the caller's
  argument variables -- as far as that makes sense.

There's a caveat there for argument expressions which don't correspond
directly to variables -- and I've glossed over the issue of lvalue
expressions which designate locations and all of that.  The idea is that
you can replace

  function mumble(a, b) { stuff in terms of a and b }
  ...
  mumble(xyz, whatever)

by

  ...
  stuff in terms of xyz and whatever

This does indeed capture Fortran, and Pascal's `var', while excluding C
and Pascal non-`var'.  Good!

So... obviously I'm going to claim that Python is pass-by-value.  Why?
Because its argument passing works the same way as its assignment.

But! (you claim) ...

 Python simply can't be pass-by-value, because it doesn't behave like
 pass-by-value in other languages (particularly C and Pascal).

Ah! (say I) but assignment in C and Pascal looks different from the way
it looks in C -- and in exactly the same way that argument passing looks
different.  And there, I think, I'm going to rest my case.

I'm sorry I took so long to distill these thoughts.  Thank you for
putting up with my theoretical meanderings on the way.

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-13 Thread Aaron Brady
On Jan 13, 5:06 pm, Mark Wooding m...@distorted.org.uk wrote:
snip
 I'm going to move away from the formal semantics stuff and try a
 different tack.  Here's what I think is the defining property of
 pass-by-value (distilled from the formal approach I described earlier,
 but shorn of the symbolism):

   The callee's parameters are /new variables/, initialized /as if by
   assignment/ from the values of caller's argument expressions.

In other words, the same as assignment in that language.

snip
 Because its argument passing works the same way as its assignment.

That would be called pass-by-assignment.  But you've just postponed
explaining yourself.  Stop delegating and work.
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-11 Thread Mark Wooding
ru...@yahoo.com ru...@yahoo.com wrote:
 Mark Wooding wrote:
  ru...@yahoo.com ru...@yahoo.com wrote:
 
  What is the observable difference between converting an
  array to a reference (pointer) to that array and passing
  the reference by value, and passing the array by reference?
 
  For one:
 
  #include stdio.h
  static size_t foo(char v[]) { return sizeof v; }
  int main(void) {
char v[sizeof(char *) * 10];
puts(foo(v) == sizeof(char *) ? pointer : reference);
return (0);
  }
 
 You are saying that because the size of the argument
 (10) is not available in the function, it cannot be
 call-by-reference?

No, I'm saying that because the parameter has pointer type, not array
type, it's a pointer being passed by value, not an array being passed by
reference.

And the size of the argument is not 10: it's 10 times as much as the
(nonzero) size of a pointer -- and therefore distinguishable on any C
implementation.

 I think fortran is accepted as the archetypal call-by-
 reference language and it does not automatically
 supply argument size information to functions.

Well and dandy; but Fortran doesn't turn arrays into pointers.

  For another:
 
  static void bar(char v[]) { char ch = 0; v = ch; }
/* type error if arrays truly passed by reference */
 
 v can be used as an array reference, e.g. v[1] = 23
 exactly as in the pass-by-reference fortran example.  And
 v can also be used as a local variable and reassigned.



 If the first option was the only one, would you not
 say C was definitely pass-by-reference (for arrays)?
 If one could only use v as a pointer (i.e. access
 the argument array as *(v+1) = 23, then I would
 say that arrays are not passed at all, only pointers
 by-value.

Your knowledge of C is clearly limited, at best.  The notations *(p + i)
and p[i] are entirely equivalent in every way, since the square-brackets
indexing operator is in fact defined in terms of pointer dereference
(6.5.2.1):

: [#2] 2 A postfix expression followed by an expression in square
: brackets [] is a subscripted designation of an element of an array
: object. The definition of the subscript operator [] is that E1[E2] is
: identical to (*((E1)+(E2))). Because of the conversion rules that
: apply to the binary + operator, if E1 is an array object
: (equivalently, a pointer to the initial element of an array object)
: and E2 is an integer, E1[E2] designates the E2-th element of E1
: (counting from zero).

Of course, because the + operator is commutative

 That both these options exist causes me to conclude
 that, for arrays, parameter passing can be viewed
 as either arrays by-reference or pointers by-value.
 
 I don't understand what relevance type checking
 has.  Since you are choosing to use v as a pointer,
 one would not expect a type error, yes?

Compare:

  void mumble(void) { char v[42]; char ch = 0; v = ch; }
 /* error: incompatible types in assignment */

It's because in the previous case v is a pointer that the compiler
doesn't mind me assigning to it.  In this case, because it's an array,
the compiler objects.

  I guess the case for pass-by-value would be a little stronger because
  one has to have passing a pointer by value anyway (since pointers
  are first-class datatypes) and that can be used to describe passing
  arrays (as you described).
 
  The difference is that the /callee/ function is different between the
  two cases.
 
  Also, notice that arrays in expressions turn into pointers in the same
  way, so function argument passing works the same way as assignment -- a
  hallmark of pass-by-value.
 
 Not in all expressions as you yourself mentioned:
  int a[10], *ap;
  sizeof a;
  sizeof ap;

Well done, you've pedantically picked up on the lapse in the first part
of the sentence (about sizeof, which as you say I've already mentioned
elsewhere) but failed to take any notice of the more important and
relevant point in the second half -- that argument passing works the
same way as assignment -- for `arrays' just as for other types.

void fa(char p[]);
void fp(char *p);
void fi(int i);

char a[10 * sizeof(char *)] = bar, aa[10 * sizeof(char *)] = splat;
char *p = foo, *pp = mumble;
int i = 42, ii = 69;

i = ii;   /* assignment of integers */
fi(ii);   /* integer call-by-value */

p = pp;   /* assignment of pointers */
fp(pp);   /* pointer call-by-value */
fa(pp);   /* pointer call-by-value again */

a = aa;   /* type error: incompatible types in assignment */
a = pp;   /* type error: incompatible types in assignment */
p = aa;   /* assignment of pointers */
fa(aa);   /* pointer call-by-value yet again */
fp(aa);   /* pointer call-by-value yet again */

Again, I refer readers to ISO 9899:1999: in particular:

  * 6.3.2.1p3 (array-to-pointer decay)
  * 6.5.2.2 (function calls)
  * 6.5.16 (assignment operator)

Since I'm getting thoroughly fed up of repeating myself on this point,
I'm simply going to assume, from now on, that anyone who offers a
disagreement without citing passages from 

Re: why cannot assign to function call

2009-01-11 Thread Aaron Brady
On Jan 10, 1:49 pm, Joe Strout j...@strout.net wrote:
 Aaron Brady wrote:
  Aaron Brady wrote:
  Possible compromise.  You can think of functions as mutation-only.
  You pass the object, and it gets a new (additional) name.  The old
  name doesn't go in.  /compromise
  That's correct.  The reference itself is passed in, not the variable (or
  expression) that held or generated the reference in the calling code.

  This is very odd, and I see it quite a bit.
  Me: You pass the object.
  Joe: That's correct.  You pass the reference.

  What was wrong with my original?

 I'm saying that I believe your idea was correct, but worded imprecisely
 (IMHO of course).  So I restated what I believed you were saying, using
 terminology which I believe to be more precise.  If nothing else, this
 gives you the opportunity to say No, that's not what I meant at all.

I believe that my summary is exceedingly beginner-oriented, you might
say colloquial.  Someone who has even a little programming experience
might find it childish.

  This is true.  (Technically, instead of variable, we should say LValue
  here -- there are things slightly more complex than simple variables
  that can serve as the left-hand side of an assignment.  So replace
  variable with lvalue above if you prefer.)

  This is a point worth making.  I want to penny-pinch every term in an
  introductory text, though, so, it's a tough call.

 Agreed.

Is a function call an lvalue in Python?  If not, descriptors are not
functions.

  M2: If 'fun()' returned a reference, you might be able to mutate the
  object that refers to.
  m2: You can sometimes mutate the object it refers to.
  C2: 'fun()' returns a reference.

  This is horrendous.
 http://en.wikipedia.org/wiki/Formal_fallacy
 http://en.wikipedia.org/wiki/Affirming_the_consequent

 I did point out that the logic was incorrect (even though the
 conclusion, in this case, happens to be true).-

You've done nothing other than restate your claim; and worse, you
disguised doing so in the form of a deduction.

  A question: Are you Joe and you Mark certain that the simplest
  possible introductory explanation makes use of the term 'reference'?

 I am.

In any explanation, there is an amount of detail omitted.  In an
introduction, it's large.  (I hold false statements should be avoided,
of course, and even misleading ones.  However the latter is widely
subject-dependent.)  Your strategy may have a net positive unifying
power, though; and we should see it if so.  I may be asking whether it
is safe and prudent to avoid (introducing) the term at the level we're
looking at (as well as what level exactly it is).

  Perhaps we can have a contest for shortest/simplest/best description
  of Python's data/variable/argument model.

 Sure -- but it judging it might be difficult, requiring some newbies and
 a test to check their comprehension (as you and I pondered once before).

I think the step of least load would be to ask those who are having
difficulty what their background is.  At worst, they lie; next worst,
there's no pattern.

  Lastly, I don't see any reason why we couldn't make both explanations
  available.  'For those coming from Java/etc; for those coming from
  C++/etc.'  They would both get read.

 Yes, except that the reference explanation applies equally well to
 anyone coming from Java, C/C++, RB, VB.NET, and probably others... I'm
 not sure to whom the other explanation would appeal, unless perhaps it's
 LISP programmers (just a guess, since those on that side of the aisle
 seem to invoke LISP more frequently).

True or not, it requires the reader to know what references are.  And,
since your definition conflicts with the C++ definition, it's not
clear that the requirement is good.

More terminology: is 'a' a variable, a reference, or an object, in
'a=2'?

It's a variable; it refers to an object.
It's a variable, which refers to an object.
It's a variable, which is a reference to an object.
It's a reference to an object.

Similarly, is '2' an expression, a reference, or an object?

It's an expression; it evaluates to an object.
It's an expression; it evaluates to a reference to an object.
It's an expression; it expresses an object.
It's an expression; it refers to an object.
It's a reference to an object.
It's an object.

I'd like to recommend we decide on unique answers, or avoid ambiguity
another way.

digression
In the case of the Socratic, non-bludgeoning, dialogue with a student,
if the student can be trusted to question intelligently, s/he can be
expected, on our telling him/er, 'a' is an object, to ask, What
object?  Whether to expect audience interaction, and what
interaction, is a big component in the choice of method of a
demonstration.
/digression

digression
 300+301+302 is 300+301+302
False

There are 10 objects created in the evaluation of this, 11 if
including 'False'.  They (their integer contents), in order, are: 300,
301, 302, then 300, 301, 302, not the same ones, again, then 

Re: why cannot assign to function call

2009-01-11 Thread Steven D'Aprano
On Sun, 11 Jan 2009 03:25:24 +, Mark Wooding wrote:

 Steven D'Aprano st...@remove-this-cybersource.com.au wrote:
 
 I don't believe it is a red-herring. As I understand it, Mark and Joe
 insist that C is pass-by-value *even in the case of arrays*, despite
 the semantics of array passing being identical to the semantics of
 pass-by- reference in (say) Pascal.
 
 But they aren't.  I've provided several examples to show this.

Here's some p-b-r code in Pascal:


program main(input, output);
  type
arraytype = array[1..2] of integer;
  var
arr: arraytype;

procedure foo(var bar: arraytype);
  begin
bar[2] := 42;
writeln(' bar = ', bar[1], ' ', bar[2]);
  end;

begin
  arr[1] := 0;
  arr[2] := 0;
  writeln(' Before: arr = ', arr[1], ' ', arr[2]);
  foo(arr);
  writeln(' After: arr = ', arr[1], ' ', arr[2]);
end.


Here's the output from running that code:


 Before: arr = 0 0
 bar = 0 42
 After: arr = 0 42



Here's the equivalent C code, as close to an exact one-to-one 
correspondence as I can come up with:


#includestdio.h

void foo(int bar[2])
{
  bar[1] = 42;
  printf(\n bar = %d %d , bar[0], bar[1]);
}

int main()
{
int arr[2]={0,0};
printf(\n Before: arr = %d %d , arr[0], arr[1]);
foo(arr);
printf(\n After: arr = %d %d , arr[0], arr[1]);
printf(\n);
return 0;
}


And the output of it:

 Before: arr = 0 0
 bar = 0 42
 After: arr = 0 42


If it walks like pass-by-reference, and smells like pass-by-reference, 
and swims like pass-by-reference, is it still your contention that it is 
pass-by-value?



 For the purpose of clearing this up once and for all: arrays, in C, are
 `don't-pass-at-all'.  There is no way -- none whatever -- of declaring a
 function parameter as having array type.

It looks just like I did precisely that here:

void foo(int bar[2])

I guess this is where you explain again that arrays in C are bizarre, 
and that while int arr[2] inside a function body means declare an 
array of two ints and call it 'arr', the exact same declaration in a 
function parameter list means something else. Possibly:

Declare a pointer which points to an array of two ints, call the pointer 
'arr', and dereference the pointer every time it is used inside the 
function as if you were referring to the array directly.

Am I close?



-- 
Steven
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-11 Thread Paul Rubin
Steven D'Aprano st...@remove-this-cybersource.com.au writes:
 If it walks like pass-by-reference, and smells like pass-by-reference, 
 and swims like pass-by-reference, is it still your contention that it is 
 pass-by-value?

Of course the C example is pass by value.  It's just that the value
being passed is an address.
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-11 Thread Aaron Brady
On Jan 11, 8:32 am, Paul Rubin http://phr...@nospam.invalid wrote:
 Steven D'Aprano st...@remove-this-cybersource.com.au writes:
  If it walks like pass-by-reference, and smells like pass-by-reference,
  and swims like pass-by-reference, is it still your contention that it is
  pass-by-value?

 Of course the C example is pass by value.  It's just that the value
 being passed is an address.

I believe, that in order for the C example to be p-b-r, you would need
the following:

void foo(var int bar[2])
{
  bar = malloc( something );
}

Such that the caller reflects the change.
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-11 Thread Steven D'Aprano
On Sun, 11 Jan 2009 06:32:31 -0800, Paul Rubin wrote:

 Steven D'Aprano st...@remove-this-cybersource.com.au writes:
 If it walks like pass-by-reference, and smells like pass-by-reference,
 and swims like pass-by-reference, is it still your contention that it
 is pass-by-value?
 
 Of course the C example is pass by value.  It's just that the value
 being passed is an address.

I believe that's exactly the way VAR (reference) parameters are 
implemented in Pascal. What's the difference?


-- 
Steven
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-11 Thread Mark Wooding
Aaron Brady castiro...@gmail.com wrote:

 True or not, it requires the reader to know what references are.  And,
 since your definition conflicts with the C++ definition, it's not
 clear that the requirement is good.

I blame C++ for coopting a perfectly good word with a established
well-understood meaning, and applying it to a half-baked and
inconsistent concept.

 More terminology: is 'a' a variable, a reference, or an object, in
 'a=2'?
 
 It's a variable; it refers to an object.
 It's a variable, which refers to an object.
 It's a variable, which is a reference to an object.
 It's a reference to an object.

It's an /identifier/ (2.3); or, if you want a shorter word, a /name/
(also 2.3).  (I'll go with `name'.)  In any given context, the name
might or might not mean something.  Names are assigned meanings by an
/environment/; if the environment assigns a meaning to a name, we say
that the name is /bound/ to that meaning; otherwise it is /unbound/.

The rules for determining the environment at any given point in a
program vary with language.  Python is fairly simple: it is /lexically
scoped/, which means that a great deal of information about the
environment can be determined simply by analysing the program text
statically.  (Compare `dynamic scope', where the environment at any
point in a program's executiondepends quite subtly on which functions
are active at that point.  The main difference is that, under lexical
scoping, a function's environment is an extension of the environment in
which it was defined, whereas under dynamic scoping a function's
environment is an extension of the environment of the caller.  Languages
can offer both kinds of scoping simultaneously: both Common Lisp and
Perl do this.)

Python is /block-structured/: various syntactic forms (/blocks/)
introduce new environments which are extensions of the environment of
the enclosing block, i.e., within the inner block, a few names are bound
to new meanings, while all the other names retain whatever meaning they
had in the enclosing block.  Names whose meanings are modified are said
to be /bound by the block/.  A name which occurs within the block is a
/bound occurrence/ if the name is bound by the block, or a /free
occurrence/ otherwise.

Python has what one might call `implicit binding': a name appearing
alone (or as part of a destructuring pattern) on the left-hand side of
an assignment which would otherwise be a free occurrence, and in the
absence of an explicit declaration such as `global' or `nonlocal', is
implicitly bound to a fresh variable by the smallest enclosing block.
Python also has explicit binding: e.g., the parameter names of a
function are explicitly bound to new variables by the function.

So, where were we?  `a = 2'.  The `a' is a name.  It appears alone on
the left-hand side of an assignment: this is therefore a candidate for
implicit binding.  Let's assume that `a' is bound to a variable, either
as a result of this or some other implicit binding, or an explicit
declaration.  (I don't believe Python has meanings other than variables
which might be bound to a name, so this is pretty safe.  Scheme, for
example, puts macros and special syntactic keywords in the same
namespace as variables, so you can, for example, lexically rebind the IF
keyword as a function, should you so wish.  This is probably a bad
idea.)

So, `a' is bound to a variable.  The variable, like all Python
variables, stores a reference.  We don't know what this reference might
be before the assignment, but afterwards, we know that it must be a
reference to an integer object representing the value 2.

This is cumbersome to talk about; in informal conversations, one often
talks about `the variable a' or even `the integer a'.  It's important to
realise that such phrases are abbreviations for convenience, and do not
directly correspond to reality.

 Similarly, is '2' an expression, a reference, or an object?

 It's an expression; it evaluates to an object.
 It's an expression; it evaluates to a reference to an object.
 It's an expression; it expresses an object.
 It's an expression; it refers to an object.
 It's a reference to an object.
 It's an object.

It's an /integer literal/ (2.4.3).  It's also an expression, because all
literals are expressions.  We can confidently predict that the value of
this expression (i.e., the result of evaluating it) is an integer object
representing the value 2.

 In the case of the Socratic, non-bludgeoning, dialogue with a student,
 if the student can be trusted to question intelligently, s/he can be
 expected, on our telling him/er, 'a' is an object, to ask, What
 object?  Whether to expect audience interaction, and what
 interaction, is a big component in the choice of method of a
 demonstration.

Declaring `a' to be an object begs many questions, such as `what type
does this object have?'.  This is an unfortunate question, because the
naive answer (e.g., from the above: `it's an integer') comes up against
the problem 

Re: why cannot assign to function call

2009-01-11 Thread Mark Wooding
Steven D'Aprano st...@remove-this-cybersource.com.au wrote:

 I guess this is where you explain again that arrays in C are bizarre, 
 and that while int arr[2] inside a function body means declare an 
 array of two ints and call it 'arr', the exact same declaration in a 
 function parameter list means something else. 

I quoted 6.7.5.3p7 before.  Please pay attention.

: A declaration of a parameter as ``array of type'' shall be adjusted to
: ``qualified pointer to type'', where the type qualifiers (if any) are
: those specified within the [ and ] of the array type derivation. If
: the keyword static also appears within the [and ] of the array type
: derivation, then for each call to the function, the value of the
: corresponding actual argument shall provide access to the first
: element of an array with at least as many elements as specified by the
: size expression.

 Declare a pointer which points to an array of two ints, call the pointer 
 'arr', and dereference the pointer every time it is used inside the 
 function as if you were referring to the array directly.

No.  Declare a pointer which points to an int, and call the pointer
`arr'.

 Am I close?

Vaguely.  A pointer to an array is not the same as a pointer to its
first element.  The former has type T (*)[N]; the latter has type T *.
The compiler entirely ignores the number (unless you write `static' --
little-known C99 feature).

There is no further magic: it's just a pointer.

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-11 Thread rurpy
Mark Wooding wrote:
 ru...@yahoo.com ru...@yahoo.com wrote:
 Mark Wooding wrote:
  ru...@yahoo.com ru...@yahoo.com wrote:
...
  For another:
 
  static void bar(char v[]) { char ch = 0; v = ch; }
/* type error if arrays truly passed by reference */

 v can be used as an array reference, e.g. v[1] = 23
 exactly as in the pass-by-reference fortran example.  And
 v can also be used as a local variable and reassigned.

 If the first option was the only one, would you not
 say C was definitely pass-by-reference (for arrays)?
 If one could only use v as a pointer (i.e. access
 the argument array as *(v+1) = 23, then I would
 say that arrays are not passed at all, only pointers
 by-value.

 Your knowledge of C is clearly limited, at best.  The notations *(p + i)
 and p[i] are entirely equivalent in every way, since the square-brackets
 indexing operator is in fact defined in terms of pointer dereference
 (6.5.2.1):
...

Yes, my C experience is limited.  I very rarely write
any C these days and even many years ago when I wrote
more, it was very vanilla stuff not requiring any deep
knowlage of dark corners of the language.

Nevertheless, I am aware of everything you wrote above
(the gist, not the standard's verbiage) and the common
demonstration of it: 3[surprised?] = 'p'.

But if you'll note, I said if ... referring to a couple
of hypothetical C-like languages, so your chapter-and-verse
quote from the standard, while interesting and appreciated,
was basically irrelevant.

...
  Also, notice that arrays in expressions turn into pointers in the same
  way, so function argument passing works the same way as assignment -- a
  hallmark of pass-by-value.

 Not in all expressions as you yourself mentioned:
  int a[10], *ap;
  sizeof a;
  sizeof ap;

 Well done, you've pedantically picked up on the lapse in the first part

It isn't pedantic.  It is the only thing (IFAIK) that
allows one to talk about variables of an array type (as
opposed to only pointers).

...
 Since I'm getting thoroughly fed up of repeating myself on this point,
 I'm simply going to assume, from now on, that anyone who offers a
 disagreement without citing passages from (at least a specific draft of)
 ISO 9899 to support any claims made is simply being wilfully ignorant --
 and therefore no longer worth my attention.

 (If you don't have a copy of any such version, may I suggest

   http://std.dkuug.dk/jtc1/sc22/open/n2794/

 citing this (confusingly) as n843, as a place to start.)

Actually I've already downloaded a C89/90 standard draft
in the hope that an earlier version would be simpler.
Since C's behavior vis call-by-x is (I presume) unchanged
back to KR, whatever it said about it should be confirmable
by any ealier versions descriptions of C.

But more importantly, we seem to be talking at cross
purposes.

My idea of a language model is a description of the
language that is precise enough to allow a model's
user to predict how any piece of code will behave when
run.

The C-standard(s) do that for C.  Since many people
would claim that a language that does not behave as
the C standard describes is not C, it is definitional,
and one cannot reasonably say that the model presented
in the C standard is incorrect. (Of course, like all
standards, the C standard is not perfect, it contains
errors and inconsistencies that require correction,
and like all languages, C evolves requiring new versions
of the standard.)

Nevertheless, I see no reason to believe, based on
anything said in this thread, or my experience in
general, that there can be *only* one correct model
of a language, or part of a language.

So all the quoting of the C standard in the world
does not address the issue: can C's array passing be
described (modeled) as pass-by-reference?
I acknowledge that the C standard provides one
(correct) model in which arrays aren't passed, only
pointers by-value.

To address the issue you need to show that an alternate
model (array passing by-reference for example) is incorrect,
i.e. leads it user to conclude that a program will behave
differently than it does.  And of course, when such a
discrepancy model and behavior is pointed out, the proposer
of the alternate model will fix it if possible.

If you can not show that an alternate model is incorrect,
then the next best thing is to show that your model is
better.  Better would involve considerations such as simpler,
consistent with other languages, easier to understand by
various categories of users, etc.  Obviously this is a
very subjective task, and one could expect disagreement.

Many of the responses by you, Joe, and others, have
an of course this model is the right one, how could
anyone think otherwise tone to them.  I hope I have
explained clearly why I think that attitude is unjustified.

Finally, and please don't be insulted by this, but to
me and many readers, you are a bunch on glowing dots
on a screen.  I have been using the internet long enough
to have any number of times read very 

Re: why cannot assign to function call

2009-01-11 Thread Mark Wooding
ru...@yahoo.com ru...@yahoo.com wrote:

 But if you'll note, I said if ... referring to a couple of
 hypothetical C-like languages, so your chapter-and-verse quote from
 the standard, while interesting and appreciated, was basically
 irrelevant.

Ah, what you actually said was still quoted above (thanks):

: v can be used as an array reference, e.g. v[1] = 23 exactly as in
: the pass-by-reference fortran example.  And v can also be used as a
: local variable and reassigned.
: 
: If the first option was the only one, would you not say C was
: definitely pass-by-reference (for arrays)?

I must have been reading too quickly and I missed the conditional here.
I'm terribly sorry. :-(

Answering the question as posed, rather than mis-read: I think the
sizeof business would still indicate that a pointer was being passed.

If the language also forbade sizeof on array-type arguments and passing
array as arguments to functions expecting pointers, then I'd say you'd
have a point.  But I'm not sure I'd agree that such a language was
`C-like' -- the bizarre behaviour of arrays is one of the language's
most distinctive features!

   Also, notice that arrays in expressions turn into pointers in the same
   way, so function argument passing works the same way as assignment -- a
   hallmark of pass-by-value.
 
  Not in all expressions as you yourself mentioned:
   int a[10], *ap;
   sizeof a;
   sizeof ap;
 
  Well done, you've pedantically picked up on the lapse in the first part
 
 It isn't pedantic.  It is the only thing (IFAIK) that allows one to
 talk about variables of an array type (as opposed to only pointers).

You can talk about /variables/ of array type, but not /expressions/ of
array type (except in very limited circumstances, as operands of sizeof
or ).

 Actually I've already downloaded a C89/90 standard draft in the hope
 that an earlier version would be simpler.  Since C's behavior vis
 call-by-x is (I presume) unchanged back to KR, whatever it said
 about it should be confirmable by any ealier versions descriptions of
 C.

It should be; but you may have to adjust the clause numbers I'm citing.
Also, the earlier version of the standard didn't have numbered
paragraphs, which makes citing specific bits more tedious.

 But more importantly, we seem to be talking at cross purposes.

We might be...

[snip]

 So all the quoting of the C standard in the world does not address the
 issue: can C's array passing be described (modeled) as
 pass-by-reference?  I acknowledge that the C standard provides one
 (correct) model in which arrays aren't passed, only pointers by-value.

 To address the issue you need to show that an alternate model (array
 passing by-reference for example) is incorrect, i.e. leads it user to
 conclude that a program will behave differently than it does.  And of
 course, when such a discrepancy model and behavior is pointed out, the
 proposer of the alternate model will fix it if possible.

I'd claim, in fact, that the proposer of an alternative model bears the
responsibility to prove it correct, i.e., in the case of C, at least
consistent with the official standard.

But I believe that I have indeed shown that the arrays-passed-by-
reference model is incorrect, by demonstrating that the called function
sees the parameter as a freshly allocated pointer and not an array: it
can be assigned (unlike an array); its size is that of a pointer; one
can take its address and manipulate its bit-pattern as if it were a
pointer.  Indeed, the standard guarantees that no strictly-conforming C
program can distinguish the parameter from a freshly allocated pointer.

And therefore I can point to my earlier (almost-formal) definitions of
pass-by-value and pass-by-reference to complete the proof: the
allocation of a new variable is inconsistent with pass-by-reference,
while it is consistent with pointer-decay followed by pass-by-value.

Of course, this is contingent on your acceptance of my definitions.  But
I don't see anyone else providing sufficiently detailed definitions to
make such proofs, and my definitions seem consistent with the way most
other languages use the terms, so I'm pretty confident that they're
good...

 Many of the responses by you, Joe, and others, have an of course this
 model is the right one, how could anyone think otherwise tone to
 them.  I hope I have explained clearly why I think that attitude is
 unjustified.

I hope that I've been doing more than that: drawing comparisons with and
borrowing concepts from other languages, attempting to solidify
definitions which otherwise seem to cause controversy, and then drawing
conclusions from these definitions to strengthen my case and weaken
others' cases.

 Finally, and please don't be insulted by this, but to me and many
 readers, you are a bunch on glowing dots on a screen.

As are we all.  (Brought to you by Sobering Thought for the Day.)

 I have been using the internet long enough to have any number of times
 read very plausible, 

Re: why cannot assign to function call

2009-01-10 Thread Steven D'Aprano
On Fri, 09 Jan 2009 20:23:11 +, Mark Wooding wrote:

 Steven D'Aprano st...@remove-this-cybersource.com.au wrote:
 
 I'm pretty sure that no other pure-Python coder has manipulated
 references either. They've manipulated objects.
 
 No: not directly.  The Python program deals solely with references;
 anything involving actual objects is mediated by the runtime.

Your claim is ambiguous: when you say the Python program, are you 
talking about the program I write using the Python language, or the 
Python VM, or something else? If the first, then you are wrong: the 
Python program I write doesn't deal with references. It deals with 
objects.

This discussion flounders because we conflate multiple levels of 
explanation. People say You do foo when they mean the Python VM does 
foo. Earlier, I responded to your claim that I was storing references by 
saying I was pretty sure I didn't store references, and gave an example 
of the line of Python code x=23. Your response was to mix explanatory 
levels:

 You bind names to locations which store immediate representations.
 Python IRs are (in the sense defined above) exclusively references.

I most certainly don't bind names to locations. When I write x=23, I 
don't know what the location of the object 23 is, so how could I bind 
that location to the name? You are conflating what the Python VM does 
with what I do. What *I* do is bind the object 23 to the name x. I don't 
know the location of 23, I don't even know if 23 has a well-defined 
location or if it is some sort of distributed virtual data structure. As 
a Python programmer, that's the level I see: names and objects.

At a lower level, what the Python VM does is store the name 'x' in a 
dictionary, bound to the object 23. No locations come into it, because at 
this level of explanation, dictionaries are an abstract mapping. There's 
no requirement that the abstract dictionary structure works by storing 
addresses. All we know is that it maps the name 'x' to the object 23 
somehow. Maybe there's no persistent storage, and the dict stores 
instructions telling the VM how to recreate the object 23 when it is 
needed. Who knows? But at this explanatory level, there are no locatives 
involved. Names and objects float as disembodied entities in the aether, 
and dicts map one to the other.

At an even lower explanatory level, the CPython implementation of 
dictionaries works by storing a pointer (or if you prefer, a reference) 
to the object in a hash table. Pointers, of course, are locatives, and so 
finally we come to the explanation you prefer. We've gone from abstract 
names-and-classes to concrete pointers-to-bytes. But this is at least two 
levels deeper than what's visible in Python code. Just about the only 
time Python coders work with locatives is when they manually calculate 
some index into a string or list, or similar.

At an even lower explanatory level, all the VM does is copy bytes. And at 
a lower level still, it doesn't even copy bytes, it just flips bits. And 
below that, we're into physics, and I won't go there.

I daresay you probably get annoyed at me when I bring up explanations at 
the level of copying bytes. You probably feel that for the average Python 
programmer, *most of the time* such explanations are more obfuscatory 
than useful. Of course, there are exceptions, such as explaining why 
repeated string concatenation is likely to be slow. There is a time and a 
place for such low level explanations, but not at the high-level overview 
needed by the average Python programmer.

And you would be right. But I argue that your explanation at the level of 
references is exactly the same: it is too low level. It relies on 
specific details which may not even be true for all implementations of 
Python. It certainly relies on details which won't be true for 
hypothetical versions of Python running on exotic hardware. One can do 
massively parallel calculations using DNA, and such DNA computers are 
apparently Turing complete. I have no idea how one would write a Python 
virtual machine in such a biological computer, but I'm pretty sure that 
data values won't have well-defined locations in a machine that consists 
of billions of DNA molecules floating in a liquid.

If that's too bizarre for you, think about simulating a Python VM in your 
own head. If we know one thing about the human brain, it is that thoughts 
and concepts are not stored in single, well-defined locations, so when 
you think of x=23, there is no pointer to a location in your head.


 That's why we should try to keep the different layers of explanation
 separate, without conflating them. Python programmers don't actually
 flip bits, and neither do they manipulate references. Python
 programmers don't have access to bits, or references. What they have
 access to is objects.
 
 No, that's my point: Python programmers /don't/ have direct access to
 objects.  The objects themselves are kept at arm's length by the
 indirection 

Re: why cannot assign to function call

2009-01-10 Thread Aaron Brady
On Jan 9, 9:30 am, Joe Strout j...@strout.net wrote:
 Aaron Brady wrote:
  Possible compromise.  You can think of functions as mutation-only.
  You pass the object, and it gets a new (additional) name.  The old
  name doesn't go in.  /compromise

 That's correct.  The reference itself is passed in, not the variable (or
 expression) that held or generated the reference in the calling code.

This is very odd, and I see it quite a bit.
Me: You pass the object.
Joe: That's correct.  You pass the reference.

What was wrong with my original?

 This is true.  (Technically, instead of variable, we should say LValue
 here -- there are things slightly more complex than simple variables
 that can serve as the left-hand side of an assignment.  So replace
 variable with lvalue above if you prefer.)

This is a point worth making.  I want to penny-pinch every term in an
introductory text, though, so, it's a tough call.

 M2: If 'fun()' returned a reference, you might be able to mutate the
 object that refers to.
 m2: You can sometimes mutate the object it refers to.
 C2: 'fun()' returns a reference.

This is horrendous.
http://en.wikipedia.org/wiki/Formal_fallacy
http://en.wikipedia.org/wiki/Affirming_the_consequent

A question: Are you Joe and you Mark certain that the simplest
possible introductory explanation makes use of the term 'reference'?
Perhaps we can have a contest for shortest/simplest/best description
of Python's data/variable/argument model.

Lastly, I don't see any reason why we couldn't make both explanations
available.  'For those coming from Java/etc; for those coming from
C++/etc.'  They would both get read.
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-10 Thread Mark Wooding
[Another tome.  I hope this contains sufficient new material to continue
to be of interest to other readers.]

Steven D'Aprano st...@remove-this-cybersource.com.au wrote:
 On Fri, 09 Jan 2009 20:23:11 +, Mark Wooding wrote:

  No: not directly.  The Python program deals solely with references;
  anything involving actual objects is mediated by the runtime.

 Your claim is ambiguous: when you say the Python program, are you
 talking about the program I write using the Python language, or the
 Python VM, or something else? 

The former.

 If the first, then you are wrong: the Python program I write doesn't
 deal with references. It deals with objects.

Do you have evidence for this claim other than your vigorous assertion?
I have evidence: in particular, after the example

  l = [1, 2, 3]
  l[1] = l

the list l (abuse of terminology: I mean `the list referred to from the
location bound to l') has the structure I drew, but you snipped:

 ,--,
 v  |
  +---++---+|
   l: | * | *- 1  |
  +---++---+|
   | *--'
   +---+
   | *- 3
   +---+

Can you explain, without using the concept of references (or anything
else equivalent) why this happens, and why the result is not (for
example) [1, [1, 2, 3], 3]?

 This discussion flounders because we conflate multiple levels of
 explanation.

No.  I'm sticking to a single level of explanation.  It may appear to be
a lower level than the one you're trying to promote, and therefore
contains more detail and is more complicated, but it has the benefit
that it explains observed phenomena.

 People say You do foo when they mean the Python VM does foo.

Since what the programmer does is type at a keyboard, the keystrokes
being interpreted eventually as editing commands in a text editor
(having been processed by various intermediate pieces of software
probably including keyboard drivers, and maybe window systems or
terminal line disciplines), anything else is an abuse of terminology;
but a useful one.

So, the programmer types, with the objective (presumably) of
constructing a text file containing a Python program which, when
executed by an appropriate Python implementation, will behave in a
satisfactory way.

The notion of `Python VM' is a good one (though potentially open to
confusion -- alas, `virtual machine' has multiple meanings too).  So: a
Python program can be interpreted as instructions to such a virtual
machine, to behave in particular ways.  Agreed?  The question is: how do
we best describe the behaviour of such a Python VM when executing a
Python program, given its text?

It's far too easy, as we've both shown, to slip into imprecise
terminology here.  When I write

  You bind names to locations which store immediate representations.
  Python IRs are (in the sense defined above) exclusively references.

I mean, of course, that a Python implementation behaves is if it binds
`names to locations which store immediate representations'.

 I most certainly don't bind names to locations. When I write x=23, I 
 don't know what the location of the object 23 is, so how could I bind 
 that location to the name?

Quite.  A lapse on my part, due to sloppy writing caused by a desire not
to make this article any longer than it already was.

 You are conflating what the Python VM does with what I do.

No...

 What *I* do is bind the object 23 to the name x. 

What you do is described above.  It doesn't involve any binding at all,
or objects.  Unless, that is, you are actually implementing Python
personally (i.e., not merely instructing a computer to do so, but
actually within your own mind); in which case I claim that you must do
so as I have described, or do so wrongly.

 I don't know the location of 23, I don't even know if 23 has a
 well-defined location

I warned that I was using certain terms in a technical sense, and
attempted to define them clearly at the top of my article.  The word
`location' was one such:

:   * A /location/[1] is an area of memory suitable for storing the
: /immediate representation/ (which I shall abbreviate to /IR/) of a
: value.  (A location may be capable of storing things other than
: IRs, e.g., representations of unevaluated expressions in lazily
: evaluated languages.  Locations may vary in size, e.g., in order
: to be capable of storing different types of IRs.)

Whether 23 has a location is unimportant.  In the context of your
example `x = 23', what's important is that the name `x' is bound to a
location, and then an immediate representation of the value `23' is
stored in that location.

(This description holds for all languages I can think of, modulo details
of which occurrences of names are binding occurrences, and C++'s user-
controlled assignment and so on.)

 or if it is some sort of distributed virtual data structure. As a
 Python programmer, that's the level I see: names and 

Re: why cannot assign to function call

2009-01-10 Thread Mark Wooding
ru...@yahoo.com ru...@yahoo.com wrote:

 Agreed.  I think the docs, especially those that develop
 the conceptual model of how Python work at runtime, could
 use some major attention.

If we can achieve consensus in this (still remarkably civil) discussion,
we might be able to amend the docs.

 I would be willing to bet that most of the confused posters do not
 distinguish between assignment operation (AO) and data model (DM).
 Their conceptual box is labeled assignment behavior and includes
 both AO and DM.  They expect that AO+DM in Python will produce the
 same results in Python as they are used to in the other languages
 they've used.  That the discrepancy comes from the DM part rather than
 the AO part is pretty irrelevant to them given that world view.

I think that we're in agreement, up to this point at least.  That's
good.

My claim is that, until they learn to distinguish these two aspects of
Python's semantics, they will remain confused.

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-10 Thread Mel
Aaron Brady wrote:

 Lastly, I don't see any reason why we couldn't make both explanations
 available.  'For those coming from Java/etc; for those coming from
 C++/etc.'  They would both get read.

That's what I was just thinking .. there are lots of others, too: for those
coming from relational database theory... would be a good one.

Mel.

--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-10 Thread rurpy
On Jan 9, 6:47 am, Mark Wooding m...@distorted.org.uk wrote:
 ru...@yahoo.com ru...@yahoo.com wrote:
  As a side comment (because it always bugs me when I read this, even
  though I read it in very authoritative sources), ISTM that C passes
  everything by value except arrays; they are passed by reference (by
  passing a pointer to the array by value.)  Admittedly, the close
  relationship between arrays and pointers makes it easy conflate them.

 Arrays are distinctly second-class citizens in C.

 Basically, in C, arrays aren't passed at all but there's some syntactic
 sugar so you can squint and con yourself that they're passed by
 reference.

 If you try to pass an array, the array name immediately decays to a
 pointer, and the pointer gets passed instead -- by value.  The
 corresponding function parameter must be a pointer to an approrpriate
 kind of thing, though you're allowed to write []s to confuse yourself if
 you like -- T D[] in a function parameter declaration means precisely
 the same as T *D -- to the extent that D has type T **D and so on.

What is the observable difference between converting an
array to a reference (pointer) to that array and passing
the reference by value, and passing the array by reference?

That is, given a C-like compiler that is the same as
C except that it passes arrays by reference, how would
it differ from an ordinary C compiler?

The choice of terminology (in this case) seems to me to
be a matter of convention rather than any fundamental
observable difference.  I guess the case for pass-by-value
would be a little stronger because one has to have passing
a pointer by value anyway (since pointers are first-class
datatypes) and that can be used to describe passing arrays
(as you described).  Adding a second mechanism,
passing-arrays-by-reference, is perhaps unnecessary,
but not wrong, and may be more easily understandable
to the target audience.
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-10 Thread Mark Wooding
ru...@yahoo.com ru...@yahoo.com wrote:

 What is the observable difference between converting an
 array to a reference (pointer) to that array and passing
 the reference by value, and passing the array by reference?

For one:

#include stdio.h

static size_t foo(char v[]) { return sizeof v; }

int main(void)
{
  char v[sizeof(char *) * 10];
  
  puts(foo(v) == sizeof(char *) ? pointer : reference);
  return (0);
}

For another:

static void bar(char v[]) { char ch = 0; v = ch; }
  /* type error if arrays truly passed by reference */

 I guess the case for pass-by-value would be a little stronger because
 one has to have passing a pointer by value anyway (since pointers
 are first-class datatypes) and that can be used to describe passing
 arrays (as you described).

The difference is that the /callee/ function is different between the
two cases.

Also, notice that arrays in expressions turn into pointers in the same
way, so function argument passing works the same way as assignment -- a
hallmark of pass-by-value.

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-10 Thread Joe Strout

ru...@yahoo.com wrote:


What is the observable difference between converting an
array to a reference (pointer) to that array and passing
the reference by value, and passing the array by reference?


The difference is whether an assignment to the formal parameter (within 
the function) affects the actual parameter (in the calling code).  If it 
does, then that's pass by reference.  If it does not, then that's pass 
by value.



That is, given a C-like compiler that is the same as
C except that it passes arrays by reference, how would
it differ from an ordinary C compiler?


Such a compiler is available: it's called C++, and it gives the 
programmer the choice to pass by value or pass by reference (the latter 
indicated by adding  to the parameter in the function declaration, 
just like you would add ByRef in RB or VB.NET).


If the parameter is called foo, and you pass in bar, then

  foo = SomeNewArray();

would change bar if it were passed by reference; it would not affect bar 
at all if it were passed by value.


The two are quite distinct.

Best,
- Joe

--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-10 Thread Joe Strout

Aaron Brady wrote:


Aaron Brady wrote:

Possible compromise.  You can think of functions as mutation-only.
You pass the object, and it gets a new (additional) name.  The old
name doesn't go in.  /compromise

That's correct.  The reference itself is passed in, not the variable (or
expression) that held or generated the reference in the calling code.


This is very odd, and I see it quite a bit.
Me: You pass the object.
Joe: That's correct.  You pass the reference.

What was wrong with my original?


I'm saying that I believe your idea was correct, but worded imprecisely 
(IMHO of course).  So I restated what I believed you were saying, using 
terminology which I believe to be more precise.  If nothing else, this 
gives you the opportunity to say No, that's not what I meant at all.



This is true.  (Technically, instead of variable, we should say LValue
here -- there are things slightly more complex than simple variables
that can serve as the left-hand side of an assignment.  So replace
variable with lvalue above if you prefer.)


This is a point worth making.  I want to penny-pinch every term in an
introductory text, though, so, it's a tough call.


Agreed.


M2: If 'fun()' returned a reference, you might be able to mutate the
object that refers to.
m2: You can sometimes mutate the object it refers to.
C2: 'fun()' returns a reference.


This is horrendous.
http://en.wikipedia.org/wiki/Formal_fallacy
http://en.wikipedia.org/wiki/Affirming_the_consequent


I did point out that the logic was incorrect (even though the 
conclusion, in this case, happens to be true).



A question: Are you Joe and you Mark certain that the simplest
possible introductory explanation makes use of the term 'reference'?


I am.


Perhaps we can have a contest for shortest/simplest/best description
of Python's data/variable/argument model.


Sure -- but it judging it might be difficult, requiring some newbies and 
a test to check their comprehension (as you and I pondered once before).



Lastly, I don't see any reason why we couldn't make both explanations
available.  'For those coming from Java/etc; for those coming from
C++/etc.'  They would both get read.


Yes, except that the reference explanation applies equally well to 
anyone coming from Java, C/C++, RB, VB.NET, and probably others... I'm 
not sure to whom the other explanation would appeal, unless perhaps it's 
LISP programmers (just a guess, since those on that side of the aisle 
seem to invoke LISP more frequently).



Best,
- Joe


--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-10 Thread Steven D'Aprano
On Sat, 10 Jan 2009 12:52:47 -0700, Joe Strout wrote:

 What is the observable difference between converting an array to a
 reference (pointer) to that array and passing the reference by value,
 and passing the array by reference?
 
 The difference is whether an assignment to the formal parameter (within
 the function) affects the actual parameter (in the calling code).  If it
 does, then that's pass by reference.  If it does not, then that's pass
 by value.

Such a definition is incomplete. You are mischaracterising call-by-
reference as defined by a single binary state: assignment either affects 
the caller, or it doesn't. If it does, it is p-b-r, if it doesn't, it's p-
b-v. According to this definition, there are no other argument passing 
strategies possible. That's an enormously broad brush by which you sweep 
away decades of comp sci terminology. Not just Barbara Liskov and pass-by-
object, but Algol's thunk-based pass-by-name and Haskell's pass-by-need.

In other words, you have created a false dichotomy between pass-by-
reference and pass-by-value.

There are actually three fundamental characteristics of pass-by-reference:

* passing a value by reference does not lead to the value being copied, 
in contrast with pass-by-value where it does;

* modifications to the value passed by reference are visible to the 
caller;

* assignments to the value passed by reference are visible to the caller.

Pascal VAR parameters have all three characteristics. Pascal non-VAR 
parameters have none of them. Python parameters have two of the three. C 
parameters (call-by-value) have none of them, except for arrays, where 
they have all three, making arrays in C behave just like Pascal pass-by-
reference VAR parameters.



-- 
Steven
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-10 Thread Rhodri James

On Sat, 10 Jan 2009 18:44:37 -, ru...@yahoo.com wrote:


What is the observable difference between converting an
array to a reference (pointer) to that array and passing
the reference by value, and passing the array by reference?


This is a red herring, though.  From either viewpoint, C
arrays are anomalous in comparison with other C data types.

--
Rhodri James *-* Wildebeeste Herder to the Masses
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-10 Thread Mark Wooding
Steven D'Aprano st...@remove-this-cybersource.com.au wrote:

 There are actually three fundamental characteristics of pass-by-reference:
 
 * passing a value by reference does not lead to the value being copied, 
 in contrast with pass-by-value where it does;
 
 * modifications to the value passed by reference are visible to the 
 caller;
 
 * assignments to the value passed by reference are visible to the
   caller.

I've given an extensive definition of pass-by-reference.  Distilling and
paraphrasing, the main characteristic is that (where possible) new
variables are not created: rather, the parameter names are bound to the
caller's variables.  All three of your above characteristics are
consequences of this one.

But your definition is also flawed: it doesn't distinguish pass-by-
reference from pass-by-value/return (where the caller's variable is
updated from the function parameter's final value when the function
returns).  The difference is detectable if you use global variables,
however:

  variable g = 1

  function foo(x):
x = 2
print g

  foo(g)
  print g

prints 1 and 1 if you use pass-by-value, 2 and 2 if you use pass-by-
reference, and 1 and 2 if you use pass-by-value/result.

(Within the framework I presented elsewhere, pass-by-value/result is
like pass-by-value, except that we update:

  s = s'''[s'''(e''(n))/l]

where s''' is the store just prior to the return, s is the store
just after the return, n is the parameter name, e'' is the function's
environment, and l is the location designated by the argument
expression, i.e., (l, s') = loc(x, e, s).  If there is no such location,
then the language may either fail to compile the call, or omit the
update operation.)

 Pascal VAR parameters have all three characteristics.

That's because they work as I've suggested.

 Pascal non-VAR parameters have none of them.

Indeed.

 Python parameters have two of the three. C parameters (call-by-value)
 have none of them, except for arrays, where they have all three,
 making arrays in C behave just like Pascal pass-by- reference VAR
 parameters.

Rubbish.  In C:

  void foo(char v[42]) { v = 0; }

Calling this function has no effect on the caller whatsoever.  I've
already explained C arrays, with reference to the ISO standard,
exhaustively: there should be no excuse for continued misunderstanding
of this point.

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-10 Thread Steven D'Aprano
On Sun, 11 Jan 2009 01:22:48 +, Rhodri James wrote:

 On Sat, 10 Jan 2009 18:44:37 -, ru...@yahoo.com wrote:
 
 What is the observable difference between converting an array to a
 reference (pointer) to that array and passing the reference by value,
 and passing the array by reference?
 
 This is a red herring, though.  From either viewpoint, C arrays are
 anomalous in comparison with other C data types.

I don't believe it is a red-herring. As I understand it, Mark and Joe 
insist that C is pass-by-value *even in the case of arrays*, despite the 
semantics of array passing being identical to the semantics of pass-by-
reference in (say) Pascal. While Mark is willing to admit that arrays are 
bizarre (his term) in C, I don't think he accepts that passing arrays 
in C is anything but pass-by-value.

I think this gets very close to the bone of the debate. It demonstrates 
that pass-by-value as Mark and Joe understand it is such a broad 
concept that it can describe any argument passing behaviour at all and 
therefore is meaningless.


-- 
Steven
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-10 Thread Mark Wooding
Steven D'Aprano st...@remove-this-cybersource.com.au wrote:

 I don't believe it is a red-herring. As I understand it, Mark and Joe 
 insist that C is pass-by-value *even in the case of arrays*, despite the 
 semantics of array passing being identical to the semantics of pass-by-
 reference in (say) Pascal. 

But they aren't.  I've provided several examples to show this.  Most
tellingly, the parameter types are different in the two cases.

 While Mark is willing to admit that arrays are bizarre (his term) in
 C, I don't think he accepts that passing arrays in C is anything but
 pass-by-value.

For the purpose of clearing this up once and for all: arrays, in C, are
`don't-pass-at-all'.  There is no way -- none whatever -- of declaring a
function parameter as having array type.

Furthermore, if (say) an argument expression consists only of an
identifier bound to an object of array type, the resulting argument
expression has pointer type, and is fully evaluated prior to the
sequence point before the function call.  I provided chapter and verse
elsewhere, and I'm getting rather fed up of repeating myself.  Certainly
a dissenting opinion should include references to at least a (specific)
draft of the ISO C standard.

 I think this gets very close to the bone of the debate. It demonstrates 
 that pass-by-value as Mark and Joe understand it is such a broad 
 concept that it can describe any argument passing behaviour at all and 
 therefore is meaningless.

I've proven (not quite rigorously, but sketched a proof, and provided
definitions which are now sufficiently formal that you can fill in the
details) that my definition of pass-by-value excludes certain
behaviours.  But, most significantly, you cannot implement `swap' given
only pass-by-value.

-- [mdw], wondering whether Hanlon's razor is getting blunt.
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-10 Thread rurpy
Mark Wooding wrote:
 ru...@yahoo.com ru...@yahoo.com wrote:

 What is the observable difference between converting an
 array to a reference (pointer) to that array and passing
 the reference by value, and passing the array by reference?

 For one:

 #include stdio.h
 static size_t foo(char v[]) { return sizeof v; }
 int main(void) {
   char v[sizeof(char *) * 10];
   puts(foo(v) == sizeof(char *) ? pointer : reference);
   return (0);
 }

You are saying that because the size of the argument
(10) is not available in the function, it cannot be
call-by-reference?

I think fortran is accepted as the archetypal call-by-
reference language and it does not automatically
supply argument size information to functions.  In
fortran, if the size of the argument is known at compile
time, the programmer explicitly declares the parameter
with the same size in the function.

  integer k(3)
  call mysub (k)
  write (unit=*, fmt=*) k(1),k(2),k(3)
  end

  subroutine mysub (x)
  integer x(3)
  do 100, i=1,3
  100   x(i) = i
  return
  end

If not, he passes the size explicitly as an argument:

  integer k(3)
  call mysub (k, 3)
  write (unit=*, fmt=*) k(1),k(2),k(3)
  end

  subroutine mysub(x, n)
  integer x(0)
  do 100, i=1,3
  100   x(i) = i
  return
  end

Obviously both these idioms translate directly into
C.  Here is the second:

 #include stdio.h
 void mysub (int k[], int n) {
int i;
for (i=0; i3; i++) {
k[i] = i; }
return; }

  main() {
int k[3];
mysub (k, 3);
printf (%i,%i,%i\n, k[0],k[1],k[2]); }

So if fortran can be call-by-reference without the
compiler passing size information, I don't see why
the above C code can't be as well.

 For another:

 static void bar(char v[]) { char ch = 0; v = ch; }
   /* type error if arrays truly passed by reference */

v can be used as an array reference, e.g. v[1] = 23
exactly as in the pass-by-reference fortran example.  And
v can also be used as a local variable and reassigned.
If the first option was the only one, would you not
say C was definitely pass-by-reference (for arrays)?
If one could only use v as a pointer (i.e. access
the argument array as *(v+1) = 23, then I would
say that arrays are not passed at all, only pointers
by-value.
That both these options exist causes me to conclude
that, for arrays, parameter passing can be viewed
as either arrays by-reference or pointers by-value.

I don't understand what relevance type checking
has.  Since you are choosing to use v as a pointer,
one would not expect a type error, yes?

 I guess the case for pass-by-value would be a little stronger because
 one has to have passing a pointer by value anyway (since pointers
 are first-class datatypes) and that can be used to describe passing
 arrays (as you described).

 The difference is that the /callee/ function is different between the
 two cases.

 Also, notice that arrays in expressions turn into pointers in the same
 way, so function argument passing works the same way as assignment -- a
 hallmark of pass-by-value.

Not in all expressions as you yourself mentioned:
 int a[10], *ap;
 sizeof a;
 sizeof ap;
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-09 Thread Steven D'Aprano
On Thu, 08 Jan 2009 18:33:50 +, Mark Wooding wrote:

 [Steven's message hasn't reached my server, so I'll reply to it here.
 Sorry if this is confusing.]
 
 Aaron Brady castiro...@gmail.com wrote:
 On Jan 8, 1:45 am, Steven D'Aprano
 ste...@remove.this.cybersource.com.au wrote:
  On Wed, 07 Jan 2009 10:17:55 +, Mark Wooding wrote:
 
   The `they're just objects' model is very simple, but gets tied up
   in knots explaining things.  The `it's all references' model is
   only a little more complicated, but explains everything.
 
  But it *over* explains, because it implies things that everybody
  knows about references in other languages that aren't true for
  Python.
 
 I addressed this elsewhere.  Summary: `pass-by-reference' is a different
 thing to `all you manipulate are references': 

You know, I've written a fair bit of Python code over the years, and I've 
never manipulated a reference *once*. Ints, strings, floats, lists, 
tuples... but references? Never.

I'm pretty sure that no other pure-Python coder has manipulated 
references either. They've manipulated objects. Whatever the VM does 
under the hood is another story.

If you insist on talking about implementations, then at least get it 
right: in Python, like every other programming language, all you do is 
flip bits. It's *all* bit flipping.

That's why we should try to keep the different layers of explanation 
separate, without conflating them. Python programmers don't actually flip 
bits, and neither do they manipulate references. Python programmers don't 
have access to bits, or references. What they have access to is objects.

(Of course, there are ways to get under the hood if you really want to.)


 Python does pass-by-value,
 but the things it passes -- by value -- are references.

If you're going to misuse pass-by-value to describe what Python does, 
*everything* is pass-by-value where the value is foo, for some foo. You 
can't have anything but pass-by-value with current computer technology, 
because computers don't actually move arguments, they only copy bytes. So 
pass-by-value becomes a meaningless term, because it describes every 
computer language imaginable, including hypothetical ones using calling 
conventions not yet invented, and therefore explains nothing.


 (The `pass-by-*' notions are confusingly named anyway.  Pass-by-name
 doesn't actually involve names at all.)

You might find them confusing, but I don't. What I find confusing is that 
people insist on misusing terminology invented for describing one type of 
behaviour in order to use it for a completely different type of behaviour 
just because of certain similarities under the hood.



  Of course it's not literally true that everybody knows that you can
  use references to implement a swap(x, y) procedure. But people coming
  from a C or Pascal background tend to assume that everything is like
  C/Pascal, and there are a lot of them. If C was a rare, unfamiliar
  language, my opposition to using the term reference would be a lot
  milder. Maybe in another five years?
 
 I agree with the comment about Pascal, but C is actually pretty similar
 to Python here.  C only does pass-by-value.

Except for arrays.


 If you want a function to
 modify your variable, you have to pass a pointer value which points to
 it.

Yes, because the variable is copied before the function sees it. So if 
you pass a struct, and modify one of the struct's fields, the caller 
doesn't see the change.

Now try that with Python, and you'll see completely different behaviour. 
(You'll have to use something *like* a struct, because Python doesn't 
have them. Try an object with attributes.)

In other words... C is call-by-value, and (according to you) Python is 
call-by-value, but they behaviour differently.


 Python has no pointer values, so you need a different hack.  The
 hack usually involves lists.  (Though it's easier in the main to return
 compound data objects like tuples.  I don't suppose that a proposal for
 true multiple return values would go down well here.  No, didn't think
 so...)

Out of curiosity, what makes Python returning tuples less true than 
true multiple return values, and what can you do with TMRVs that you 
can't do with tuples?


  Okay, the abstraction has leaked again... are the paperweights
  references to the objects, or the names we've bound objects to? I'm
  confused...
 
 They're the references to the objects.  You don't bind names to objects.

Amazing. It sure feels like it to me.

x = 23

There's a name, and an object, and I've bound the name to the object so I 
can refer to the object 23 by the name x.


  You bind names slots in which you store references.

I'm pretty sure I don't. I'd have noticed.



You may have missed my last question:

  How do we deal with anonymous objects in your model?



 What I am pretty sure of is that references are going to have to enter
 the picture at some point, because other models get too complicated.

Well, I dare 

Re: why cannot assign to function call

2009-01-09 Thread Aaron Brady
On Jan 9, 4:01 am, Steven D'Aprano st...@remove-this-
cybersource.com.au wrote:
 On Thu, 08 Jan 2009 18:33:50 +, Mark Wooding wrote:
  [Steven's message hasn't reached my server, so I'll reply to it here.
  Sorry if this is confusing.]

  Aaron Brady castiro...@gmail.com wrote:
  On Jan 8, 1:45 am, Steven D'Aprano
  ste...@remove.this.cybersource.com.au wrote:
   On Wed, 07 Jan 2009 10:17:55 +, Mark Wooding wrote:

The `they're just objects' model is very simple, but gets tied up
in knots explaining things.  The `it's all references' model is
only a little more complicated, but explains everything.

   But it *over* explains, because it implies things that everybody
   knows about references in other languages that aren't true for
   Python.

  I addressed this elsewhere.  Summary: `pass-by-reference' is a different
  thing to `all you manipulate are references':

 You know, I've written a fair bit of Python code over the years, and I've
 never manipulated a reference *once*. Ints, strings, floats, lists,
 tuples... but references? Never.
snip
 That's why we should try to keep the different layers of explanation
 separate, without conflating them. Python programmers don't actually flip
 bits, and neither do they manipulate references. Python programmers don't
 have access to bits, or references. What they have access to is objects.
snip
   How do we deal with anonymous objects in your model?
  What I am pretty sure of is that references are going to have to enter
  the picture at some point, because other models get too complicated.

 Well, I dare say that at *some* point all models are insufficient. The
 map is not the territory, and there's always something that gets left
 out. But I think your model with strings is more complicated: robots,
 sticky Blu-Tack, string that you can't touch or see, and so forth.
 Compared to that, TARDIS technology enabling objects to be in two places
 at once is remarkably straightforward. Despite it being physically
 unrealistic, it's logically simple.

 --
 Steven

Possible compromise.  You can think of functions as mutation-only.
You pass the object, and it gets a new (additional) name.  The old
name doesn't go in.  /compromise

Regardless, IMO, references don't add any explanatory power; they just
make you feel cocky that you know what they are.

M: If 'fun()' returned a reference, you would be able to assign to it.
m: You can't assign to it.
C: It doesn't return a reference.

-- Why can't I assign to a function call?
-- Python variables are references only.
-- Ok, why can't I assign to a function call?
-- [Explanation Steven is trying to give.]

In other words, Mark and Joe, cut to the chase.  You're shirking.
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-09 Thread Joe Strout

ru...@yahoo.com wrote:


  a = array (1,2,3)
  b = a
  a[1] = 4
  print b

C, C++, VBA, Fortran, Perl:  1, 2, 3
Python:  1, 4, 3

You are mistaken


I don't think so.
See http://groups.google.com/group/comp.lang.python/msg/f99d5a0d8f869b96
The code I quoted there was tested.
In the C/C++ case, array-to-pointer coercion confuses
the issue so I embedded the array in a struct which
is more like an object.


No, that's cheating (IMHO).  Structs used directly (rather than via
pointers) are the odd beast, and while they're certainly possible in C,
they are far from the normal idiom.  And certainly embedding an array in
a struct just to force it to be copied, avoiding the standard reference
semantics, is an arbitrary trick.

I never claimed that you *couldn't* have copy semantics in C; you can do
almost anything you want in C (or C++).  But the *normal* usage of an
array is via a pointer, in which case the semantics are exactly the same
as in Python, Java, REALbasic, .NET, etc.


(Keep in mind
my point was not to show the behavior of arrays, but to
show that several common languages *do not* use Python's
*all* names are references model -- though of course
this does not preclude their having some Python-like
assignments since they all have some way of doing
references.)


Ah.  OK then, I guess I missed you're point.  You're absolutely right;
many languages have both reference types and value types.  Python is a
bit unusual in that it has only reference types.  I would have picked a
different example to illustrate that, but it's true nonetheless.

Best,
- Joe



--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-09 Thread Joe Strout

Aaron Brady wrote:


Possible compromise.  You can think of functions as mutation-only.
You pass the object, and it gets a new (additional) name.  The old
name doesn't go in.  /compromise


That's correct.  The reference itself is passed in, not the variable (or 
expression) that held or generated the reference in the calling code.


This is no different from, in C, passing an integer:

void foo(int bar) {
   bar = 42;
}
int baz = 0;
foo(baz);

This doesn't change baz because, speaking precisely, baz wasn't passed 
to foo -- only the *value* of baz (i.e. 0) was passed to foo.  Within 
foo, that value was stored in bar.  Assigning a new value to bar does 
not affect foo.


It's the exact same thing when the value happens to be a reference to an 
object:


typedef SomeClass* SomeClassPtr;
void foo(SomeClassPtr bar) {
   bar = new SomeClass();
}
SomeClassPtr baz = NULL;
foo(baz);

Again, we're not passing baz into foo; we're passing the *value* of baz 
(i.e. NULL) into foo.  That value is stored in bar within foo, and when 
we assign a new value (a reference to a freshly minted SomeClass object) 
into bar, of course it doesn't affect baz.



Regardless, IMO, references don't add any explanatory power; they just
make you feel cocky that you know what they are.


Nonsense.  They are the simple and clear explanation of what's going on.


M: If 'fun()' returned a reference, you would be able to assign to it.
m: You can't assign to it.
C: It doesn't return a reference.


C is false because M is false (at least, in the way I believe you mean 
it).  Or, more precisely, both M and m are nonsensical; what does it 
mean to assign to a reference?  It makes no sense.  What would it mean 
to assign to 42?


You don't assign to references any more than you assign to integers or 
assign to strings or assign to None.  Those are all values, and you 
don't assign to values -- you assign to variables.  Assign means to 
give a new value to a variable, i.e. to let (or cause) a variable to 
have a new value.  (Ye olde BASIC even used the LET keyword to indicate 
this, e.g. LET X = 42.)  Speaking casually, we don't always make this 
distinction, but I think precision is needed here.


So, I see two ways to make sense of your argument:

M1: If 'fun()' returned a variable, you would be able to assign to it.
m1: You can't assign to it.
C1: It doesn't return a variable.

This is true.  (Technically, instead of variable, we should say LValue 
here -- there are things slightly more complex than simple variables 
that can serve as the left-hand side of an assignment.  So replace 
variable with lvalue above if you prefer.)


Or, the other way some may see it is:

M2: If 'fun()' returned a reference, you might be able to mutate the 
object that refers to.

m2: You can sometimes mutate the object it refers to.
C2: 'fun()' returns a reference.

This is true (though the logic is flawed, but fixable).


-- Why can't I assign to a function call?
-- Python variables are references only.
-- Ok, why can't I assign to a function call?


You're right, Python variables are references only has nothing to do 
with it.  In a language where the only data type were integer, you 
wouldn't be able to assign to a function call either.


You can't assign to a function call because a function call is not 
itself an lvalue, and it doesn't return an lvalue.  That's just not 
something you can get for free from the type model; it's an extra 
feature that would have to be built into the language somehow, and 
Python doesn't have it.


If assignment were an operator rather than a statement, and could be 
overridden in a class via some specially-named method -- or, for that 
matter, if the assignment statement looked for such a method when it 
finds an object reference on the left-hand side -- then any object could 
be an lvalue, and you COULD (in some cases) assign to the result of a 
function.  But it's not and it doesn't.


Best,
- Joe


--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-09 Thread Mark Wooding
ru...@yahoo.com ru...@yahoo.com wrote:

 As a side comment (because it always bugs me when I read this, even
 though I read it in very authoritative sources), ISTM that C passes
 everything by value except arrays; they are passed by reference (by
 passing a pointer to the array by value.)  Admittedly, the close
 relationship between arrays and pointers makes it easy conflate them.

Arrays are distinctly second-class citizens in C.

Basically, in C, arrays aren't passed at all but there's some syntactic
sugar so you can squint and con yourself that they're passed by
reference.

If you try to pass an array, the array name immediately decays to a
pointer, and the pointer gets passed instead -- by value.  The
corresponding function parameter must be a pointer to an approrpriate
kind of thing, though you're allowed to write []s to confuse yourself if
you like -- T D[] in a function parameter declaration means precisely
the same as T *D -- to the extent that D has type T **D and so on.

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-09 Thread Steve Holden
Joe Strout wrote:
 Aaron Brady wrote:
 
 Possible compromise.  You can think of functions as mutation-only.
 You pass the object, and it gets a new (additional) name.  The old
 name doesn't go in.  /compromise
 
 That's correct.  The reference itself is passed in, not the variable (or
 expression) that held or generated the reference in the calling code.
 
 This is no different from, in C, passing an integer:
 
 void foo(int bar) {
bar = 42;
 }
 int baz = 0;
 foo(baz);
 
 This doesn't change baz because, speaking precisely, baz wasn't passed
 to foo -- only the *value* of baz (i.e. 0) was passed to foo.  Within
 foo, that value was stored in bar.  Assigning a new value to bar does
 not affect foo.
 
 It's the exact same thing when the value happens to be a reference to an
 object:
 
 typedef SomeClass* SomeClassPtr;
 void foo(SomeClassPtr bar) {
bar = new SomeClass();
 }
 SomeClassPtr baz = NULL;
 foo(baz);
 
 Again, we're not passing baz into foo; we're passing the *value* of baz
 (i.e. NULL) into foo.  That value is stored in bar within foo, and when
 we assign a new value (a reference to a freshly minted SomeClass object)
 into bar, of course it doesn't affect baz.
 
 Regardless, IMO, references don't add any explanatory power; they just
 make you feel cocky that you know what they are.
 
 Nonsense.  They are the simple and clear explanation of what's going on.
 
 M: If 'fun()' returned a reference, you would be able to assign to it.
 m: You can't assign to it.
 C: It doesn't return a reference.
 
 C is false because M is false (at least, in the way I believe you mean
 it).  Or, more precisely, both M and m are nonsensical; what does it
 mean to assign to a reference?  It makes no sense.  What would it mean
 to assign to 42?
 
 You don't assign to references any more than you assign to integers or
 assign to strings or assign to None.  Those are all values, and you
 don't assign to values -- you assign to variables.  Assign means to
 give a new value to a variable, i.e. to let (or cause) a variable to
 have a new value.  (Ye olde BASIC even used the LET keyword to indicate
 this, e.g. LET X = 42.)  Speaking casually, we don't always make this
 distinction, but I think precision is needed here.
 
 So, I see two ways to make sense of your argument:
 
 M1: If 'fun()' returned a variable, you would be able to assign to it.
 m1: You can't assign to it.
 C1: It doesn't return a variable.
 
 This is true.  (Technically, instead of variable, we should say LValue
 here -- there are things slightly more complex than simple variables
 that can serve as the left-hand side of an assignment.  So replace
 variable with lvalue above if you prefer.)
 
 Or, the other way some may see it is:
 
 M2: If 'fun()' returned a reference, you might be able to mutate the
 object that refers to.
 m2: You can sometimes mutate the object it refers to.
 C2: 'fun()' returns a reference.
 
 This is true (though the logic is flawed, but fixable).
 
 -- Why can't I assign to a function call?
 -- Python variables are references only.
 -- Ok, why can't I assign to a function call?
 
 You're right, Python variables are references only has nothing to do
 with it.  In a language where the only data type were integer, you
 wouldn't be able to assign to a function call either.
 
 You can't assign to a function call because a function call is not
 itself an lvalue, and it doesn't return an lvalue.  That's just not
 something you can get for free from the type model; it's an extra
 feature that would have to be built into the language somehow, and
 Python doesn't have it.
 
 If assignment were an operator rather than a statement, and could be
 overridden in a class via some specially-named method -- or, for that
 matter, if the assignment statement looked for such a method when it
 finds an object reference on the left-hand side -- then any object could
 be an lvalue, and you COULD (in some cases) assign to the result of a
 function.  But it's not and it doesn't.
 
Pretty soon you guys will have me believing Python doesn't work ...

regards
 Steve
-- 
Steve Holden+1 571 484 6266   +1 800 494 3119
Holden Web LLC  http://www.holdenweb.com/

--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-09 Thread Steven D'Aprano
On Fri, 09 Jan 2009 08:30:46 -0700, Joe Strout wrote:

 That's correct.  The reference itself is passed in, not the variable (or
 expression) that held or generated the reference in the calling code.
 
 This is no different from, in C, passing an integer:
 
 void foo(int bar) {
 bar = 42;
 }
 int baz = 0;
 foo(baz);
 
 This doesn't change baz because, speaking precisely, baz wasn't passed
 to foo -- only the *value* of baz (i.e. 0) was passed to foo.

We can check whether bar and baz are the same thing, by printing their 
addresses:

#includestdio.h
void foo(int bar) {
  printf(\n The address of bar is %p , bar);
  bar = 42;
}

int main() {
int baz = 0;
printf(\n The address of baz is %p , baz);
foo(baz);
return 0;
}


When I do this, I get:

 The address of baz is 0xbfa72870
 The address of bar is 0xbfa72850

So we can agree that baz and bar are different entities. Now, would 
anyone like to take a small wager on what the equivalent code in CPython 
would print?


def foo(bar):
  print  The address of bar is %s  % id(bar)
  bar = 42

baz = 0
print  The address of baz is %s  % id(baz)
foo(baz)


When I execute this, I get

 The address of baz is 143599468
 The address of bar is 143599468

Python doesn't do the same thing as C. It actually passes the same value 
to the function, without copying it.

Why oh why do you keep insisting that Python is no different from C?


Let's try one more. In C:

#include stdio.h
#include stdlib.h

struct record {
  int x;
};

void mutate(struct record bar) {
  printf(\n The address of bar is %p , bar);
  bar.x = 0;
  printf(\n Inside: %d , bar.x);
}

struct record baz;

int main(void) {
  baz.x = 1;
  printf(\n The address of baz is %p , baz);
  printf(\n Before: %d , baz.x);
  mutate(baz);
  printf(\n After: %d , baz.x);
  return 0;
}


gives output: 

 The address of baz is 0x80496fc
 Before: 1
 The address of bar is 0xbfb8f980
 Inside: 0
 After: 1


We can clearly see that baz and bar are different entities, and changes 
made to bar inside the function don't affect baz.

A Python equivalent:

class struct: pass

def mutate(bar):
  print  The address of bar is %d  % id(bar)
  bar.x = 0;
  print  Inside: %d  % bar.x

baz = struct()
baz.x = 1
print  The address of baz is %d  % id(baz)
print  Before: %d  % baz.x
mutate(baz)
print  After: %d  % baz.x


which gives output:

 The address of baz is 3085537420
 Before: 1
 The address of bar is 3085537420
 Inside: 0
 After: 0



Why oh why do you keep insisting that Python is no different from C?


-- 
Steven
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-09 Thread rurpy
Joe Strout wrote:
 ru...@yahoo.com wrote:

   a = array (1,2,3)
   b = a
   a[1] = 4
   print b

 C, C++, VBA, Fortran, Perl:  1, 2, 3
 Python:  1, 4, 3
 You are mistaken

 I don't think so.
 See http://groups.google.com/group/comp.lang.python/msg/f99d5a0d8f869b96
 The code I quoted there was tested.
 In the C/C++ case, array-to-pointer coercion confuses
 the issue so I embedded the array in a struct which
 is more like an object.

 No, that's cheating (IMHO).  Structs used directly (rather than via
 pointers) are the odd beast, and while they're certainly possible in C,
 they are far from the normal idiom.  And certainly embedding an array in
 a struct just to force it to be copied, avoiding the standard reference
 semantics, is an arbitrary trick.

It was intended as a purely rhetorical device to
avoid requiring a lot of verbiage to say why a
struct example is used for C and arrays for the
others and why that makes no difference to my point.
Actually, the whole code/results thing was purely
for effect since I presume most people reading already
understand how assignments work in these languages,
or that least that there are significant languages
using copy-like assignments.

 I never claimed that you *couldn't* have copy semantics in C; you can do
 almost anything you want in C (or C++).  But the *normal* usage of an
 array is via a pointer, in which case the semantics are exactly the same
 as in Python, Java, REALbasic, .NET, etc.

Arrays are the only datatype in C that don't use
copy-like assignment.  Everything else does.

(Keep in mind
 my point was not to show the behavior of arrays, but to
 show that several common languages *do not* use Python's
 *all* names are references model -- though of course
 this does not preclude their having some Python-like
 assignments since they all have some way of doing
 references.)

 Ah.  OK then, I guess I missed you're point.  You're absolutely right;
 many languages have both reference types and value types.  Python is a
 bit unusual in that it has only reference types.  I would have picked a
 different example to illustrate that, but it's true nonetheless.

If one accepts that there are a lot of people
who post in here that clearly are surprised by
Python's assignment semantics, and further appear
to expect assignment to have copy-like semantics,
then where is that expectation coming from?

How would anyone develop that expectation if (from
a different post in this thread), [Python's] idea
of assignment is the same as anyone else's.

If you maintain that reference-like assignment
is very common and something every programmer is
accustomed to, then where are they getting the
copy-like assignment expectations from?

I agree that most of the time, when one is using
large (memory) composite objects, and one needs
to pass, or access them by different names, one will
often use references to do so in order to avoid
expensive copies or to get desired shared behavior.
But (with the exception of C arrays [*1]), doing so
requires some special syntax in all the languages I
mentioned (AFAIK).

So it still seems to me that this is a likely
explanation to why there is frequent misunderstanding
of Python's assignments, and why responding to such
misunderstandings with, Python's assignments are
the same as other languages', is at best not helpful.

[*1]
I have often wished that C handled arrays the same
way it does structs.  I am sure that the pointer-array
pseudo-equivalence seemed like a very clever idea at
the time but I wonder if Dennis Richie ever had second
thoughts about it.
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-09 Thread Joe Strout

ru...@yahoo.com wrote:


I never claimed that you *couldn't* have copy semantics in C; you can do
almost anything you want in C (or C++).  But the *normal* usage of an
array is via a pointer, in which case the semantics are exactly the same
as in Python, Java, REALbasic, .NET, etc.


Arrays are the only datatype in C that don't use
copy-like assignment.  Everything else does.


No, arrays are just one reference type; pointers are another (and in 
most ways, these are the same thing).  When dealing with objects in C++, 
one routinely handles them with pointers, so that's the use case which 
is analogous to Python -- all the value types can be ignored for the 
sake of comparison.  (C is not an OOP language, of course, but even 
there, all but the most trivial of structs are usually allocated on the 
heap and passed around via pointers, just like in C++, Java, .NET, RB, 
and Python.)



Ah.  OK then, I guess I missed you're point.  You're absolutely right;
many languages have both reference types and value types.  Python is a
bit unusual in that it has only reference types.  I would have picked a
different example to illustrate that, but it's true nonetheless.


If one accepts that there are a lot of people
who post in here that clearly are surprised by
Python's assignment semantics, and further appear
to expect assignment to have copy-like semantics,
then where is that expectation coming from?


I think it comes from people stumbling across posts in this forum 
claiming that Python has unusual assignment semantics.  I wish people 
would stop saying that, as it causes a lot of confusion.



How would anyone develop that expectation if (from
a different post in this thread), [Python's] idea
of assignment is the same as anyone else's.


I can think of two ways:

1. They're new to programming in general, and would have had the same 
expectation for any other language.  OR,


2. They already understand some other language, and then they come here 
and read wild claims that Python's assignment and parameter-passing 
semantics are different from other languages.  Duped by this claim, they 
 conclude that, if it's unlike other languages, then Python must have 
copy semantics.



If you maintain that reference-like assignment
is very common and something every programmer is
accustomed to, then where are they getting the
copy-like assignment expectations from?


Reference-like assignment IS very common (see 
http://www.strout.net/info/coding/valref/).  So, see above.



I agree that most of the time, when one is using
large (memory) composite objects, and one needs
to pass, or access them by different names, one will
often use references to do so in order to avoid
expensive copies or to get desired shared behavior.


Right.


But (with the exception of C arrays [*1]), doing so
requires some special syntax in all the languages I
mentioned (AFAIK).


Whether you consider it special or not, pointers are extremely common 
in C.  Even more so in C++, which is the closest thing to an OOP 
language in the list of moldy languages you mentioned.


You also mentioned VBA -- if that's anything like VB, it does NOT 
require any special syntax; a variable is a reference type if its 
declared type is a class or string, and a simple type if it's anything 
else (just like in .NET, Java, and REALbasic).



So it still seems to me that this is a likely
explanation to why there is frequent misunderstanding
of Python's assignments, and why responding to such
misunderstandings with, Python's assignments are
the same as other languages', is at best not helpful.


I don't think so.  More likely, people are being confused by the claim 
that Python's assignments are NOT like other languages, when in fact 
they are.


Best,
- Joe


--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-09 Thread Mark Wooding
[Sigh.  I must apologize for the length of this article.  I can't, alas,
see a satisfactory way of trimming it.  The doubly-quoted stuff later on
was by me.]

Steven D'Aprano st...@remove-this-cybersource.com.au wrote:

 I'm pretty sure that no other pure-Python coder has manipulated 
 references either. They've manipulated objects.

No: not directly.  The Python program deals solely with references;
anything involving actual objects is mediated by the runtime.

 Whatever the VM does under the hood is another story.

(And, to stave off a return to the discussion about synchronized clones
and other implementation techniques, whether a reference is a memory
pointer, a tagged immutable immediate value, or an element of an
equivalence-class of clones is an irrelevant implementation detail; but
the reference needs to exist to explain observed, specified behaviour.
For the purposes of this discussion, I shall continue to use the
commonly accepted term `reference' to denote an arbitrary and
implementation-specific choice of the isomorphism class of such possible
implementation techniques.)

 That's why we should try to keep the different layers of explanation
 separate, without conflating them. Python programmers don't actually
 flip bits, and neither do they manipulate references. Python
 programmers don't have access to bits, or references. What they have
 access to is objects.

No, that's my point: Python programmers /don't/ have direct access to
objects.  The objects themselves are kept at arm's length by the
indirection layer of references.  

 (Of course, there are ways to get under the hood if you really want
 to.)

Yes, but -- as I've done throughout this discussion -- I shall continue
to use only Python examples whose behaviour is fully specified and
implementation independent in order to support my thesis.

  Python does pass-by-value, but the things it passes -- by value --
  are references.
 
 If you're going to misuse pass-by-value to describe what Python does, 
 *everything* is pass-by-value where the value is foo, for some foo.

No.  I've tried explaining this before, with apparently little success.
This is probably my fault: I don't seem to be good at explaining
concepts to people whose mindset is significantly different to mine.
(My refusal to ignore complicated corner cases doesn't help.)

The words `value' and `reference' have significantly different meanings
depending on whether we're talking on the one hand about data models and
on the other hand about argument-passing models.  In particular, the
latter focuses on details at a lower abstraction level.  This is
extremely unfortunate, and is causing a lot of confusion.  I can only
speculate that the origins of this mess are historical and have their
origins in the fact that lower-level languages have tended to have more
exotic argument-passing models.

This is going to be (as far as I can make it) a language-independent
survey.  That in itself is going to make matters complicated, because I
know a lot of programming languages, and they differ in sometimes subtle
ways.

Enough of the disclaimers, and on to some terminology.  For the
avoidance of confusion, I shall use the following terms in perhaps
technical senses, defined below.  Even so, I believe that I'm using
these terms in the senses (or at least, in ways similar to the senses)
commonly understood in the field of programming language design.

  * A /value/ is an item of data.  The range and nature of values is
language specific.  Typically, values encompass at least some kinds
of numbers, textual data, and compound data structures; they may
also include behavioural items such as functions.

  * A /location/[1] is an area of memory suitable for storing the
/immediate representation/ (which I shall abbreviate to /IR/) of a
value.  (A location may be capable of storing things other than IRs,
e.g., representations of unevaluated expressions in lazily evaluated
languages.  Locations may vary in size, e.g., in order to be capable
of storing different types of IRs.)

  * A /variable/ is a location to which has been /bound/ a name.  Given
an occurrence of a name in a program's source, there is a language
specific rule for determining the variable to which it is bound.

  * /Evaluation/ is the process of determining a value from an
expression.  The /value of/ an expression is the result of
evaluating the expression.  This value is, in general, dependent on
the contents of the locations to which names appearing in the
expression are bound.

  * A /function/ (synonymously, /procedure/) is a subprogram which may
be /called/ by another (not necessarily distinct) part of the
program, supplying zero or more /arguments/, performing a
computation depending on these arguments, and returning zero or more
/results/.  Whether functions are values is language specific.  The
nature of the arguments and results is language specific.


Re: why cannot assign to function call

2009-01-09 Thread Mark Wooding
Aaron Brady castiro...@gmail.com wrote:

 Possible compromise.  You can think of functions as mutation-only.
 You pass the object, and it gets a new (additional) name.  The old
 name doesn't go in.  /compromise

Huh?  That doesn't explain circular data structures at all, unless your
idea of `name' is unrelated to the identifiers the programmer has typed
and in fact is the same as what I'm calling a reference.

 Regardless, IMO, references don't add any explanatory power; they just
 make you feel cocky that you know what they are.

No, they're essential to understanding sharing and circular data.

 M: If 'fun()' returned a reference, you would be able to assign to it.

[mdw]: Why would you think that you can assign to a reference?  You
assign to variables, not references.

 -- Why can't I assign to a function call?
 -- Python variables are references only.

You may have missed this, but I explained at least twice: variables are
bound to `slots' or `locations'; locations, in Python, store references
to values; references are not values.

But I answered this lot ages ago.  I'm still dealing with the fallout
because of my approach, though.

 In other words, Mark and Joe, cut to the chase.  You're shirking.

I'm trying to explain somewhat complex concepts in defence of my thesis.
This is not intended to be an answer to the original poster: the
discussion has become considerably more technical since then.

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-09 Thread Mark Wooding
Steven D'Aprano st...@remove-this-cybersource.com.au wrote:

 Python doesn't do the same thing as C. It actually passes the same value 
 to the function, without copying it.
 
 Why oh why do you keep insisting that Python is no different from C?

I'm beginning to think that you're not bothing to read what I'm writing,
but I'll assume instead that I'm just not writing clearly enough.

In one respect, C and Python are alike.  That respect is that they both
pass arguments to functions `by value'.

In another respect, C and Python are different.  That respect is that
they represent these arguments differently: C stores a binary
representation of the value directly in the object allocated to store it
(6.2.6.1); whereas Python stores a reference to the actual value (3.1,
4.1).

This is what I mean when I say that Python passes arguments by value --
but the `values' that are passed are references.

References to the C standard are to ISO 9899:1999, though I'm fairly
sure that N843 and N1256 will do as well; references to the Python
Language Reference are to the 2.5.2 version dated 2008-02-21.

I'll note here that the PLM uses the term `binding' in the usual sense
understood by the larger programming-language community, and not as a
confusing synonym for assignment.

 Why oh why do you keep insisting that Python is no different from C?

Why oh why do you keep insisting that, because I claim that the two
languages are alike in one respect, that I believe that they must be
alike in a different respect, despite my repeated assertions to the
contrary?

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-09 Thread Mark Wooding
ru...@yahoo.com ru...@yahoo.com wrote:

 If one accepts that there are a lot of people who post in here that
 clearly are surprised by Python's assignment semantics, 

But one should not accept that.  One might accept that there are many
who post who claim that they are surprised by Python's assignment
semantics.  Such people are wrong, however, since what they are
surprised by is Python's data model, and one reason that they are
surprised by Python's data model is because it's not actually explained
very well.

 and further appear to expect assignment to have copy-like semantics,

This expectation is justified and, indeed, satisfied.  Python does, most
definitely, copy on assignment.  What it copies is references, however.
This might be clearer if the data model were explained better.

As an aside, I don't notice anywhere near as much confusion in Lisp and
Scheme groups, which might be surprising since Lisp and Scheme have
precisely the same data model, argument passing convention, and
assignment semantics, as Python has.  There are many possible
explanations:

  * The Lisp and Scheme communities are smaller.  This is certainly
true.  But it wouldn't explain what appears to be a disproportionate
level of confusion on the topic among Python beginners.

  * Individuals in the Lisp and Scheme communities are cleverer and/or
more widely experienced.  One might make an argument that this is
true and a result of the relative community sizes -- basically a
result of self-selection.  But instead I'll reject this as an
explanation.  It's arrogant and unproven.

  * The Lisp and Scheme communities make a concerted effort to explain
their data model clearly and precisely.  They accept that it's
actually quite complicated and, rather than pretend that it isn't,
explain the complexity and the benefits it brings that make the
complexity worthwhile.  I think this is the likely one.

 then where is that expectation coming from?

 How would anyone develop that expectation if (from a different post in
 this thread), [Python's] idea of assignment is the same as anyone
 else's.

Because they've fundamentally misunderstood the data model.  The very
fact that their confusion is ascribed to the wrong thing is strongly
indicative of this.

 If you maintain that reference-like assignment is very common and
 something every programmer is accustomed to, then where are they
 getting the copy-like assignment expectations from?

But it's not just assignment that deals with references.  It's argument
passing and storage of compound data as well.  (See PLR 3.1.)

They expect that assignment copies stuff, because that's what assignment
does.  Everywhere that I can think of -- except C++, which leaves
assignment semantics in hands of the programmer.  What they're confused
about is what, precisely, it is that gets copied.  And that, really, is
a result of an inadequate understanding of the data model.

 I agree that most of the time, when one is using large (memory)
 composite objects, and one needs to pass, or access them by
 different names, one will often use references to do so in order to
 avoid expensive copies or to get desired shared behavior.  But (with
 the exception of C arrays [*1]), doing so requires some special syntax
 in all the languages I mentioned (AFAIK).

Ummm... you mentioned C, C++, `Python, Java, REALbasic, .NET'.

Well, C we've dealt with.  C++ is weird.  Python we all know, and is the
main subject of the argument.  REALbasic I don't know at all, but BASICs
traditionally represent data fairly directly (rather than via
references) so will largely be like C.  .NET isn't a language at all:
rather, it's a virtual machine, runtime system, class library and family
of languages each of which may have idiosyncratic semantics.

Which leaves Java.  Java divides the world into `primitive' and
`reference' types (4.1).  The former are represented directly; the
latter have a pointer to the true data as immediate representation.  But
observe that Java's primitive types are integer types (including its
misnamed `char'), floating-point types, and booleans.  Equivalent
objects of all of these are immutable in Python -- and there is no
observable difference (unless exposed by an operator like `is' or the
`id' built-in) between a directly represented object and an /immutable/
object represented by reference.  (I've no doubt that the original
language designers were aware of this equivalence, so it's a mystery to
me precisely why they specified the language as they did rather than
leaving the messy business of boxing and unboxing primitive values to
the compiler, which, given Java's mandatory type annotations, should
have found the job trivial.)

 So it still seems to me that this is a likely explanation to why there
 is frequent misunderstanding of Python's assignments, and why
 responding to such misunderstandings with, Python's assignments are
 the same as other languages', is at best not 

Re: why cannot assign to function call

2009-01-09 Thread Joe Strout

Mark Wooding wrote:


As an aside, I don't notice anywhere near as much confusion in Lisp and
Scheme groups, which might be surprising since Lisp and Scheme have
precisely the same data model, argument passing convention, and
assignment semantics, as Python has.


Nor is there anywhere near as much confusion in the REALbasic community 
(with which I'm most familiar), which also has the same semantics for 
reference types (which in RB is everything except numbers, colors, and 
Boolean).


Apparently there is occasionally a little confusion in the Java 
community, but it rarely reaches the sillyness proportions seen here:

http://javadude.com/articles/passbyvalue.htm


  * The Lisp and Scheme communities are smaller.  This is certainly
true.  But it wouldn't explain what appears to be a disproportionate
level of confusion on the topic among Python beginners.

  * Individuals in the Lisp and Scheme communities are cleverer and/or
more widely experienced.  One might make an argument that this is
true and a result of the relative community sizes -- basically a
result of self-selection.  But instead I'll reject this as an
explanation.  It's arrogant and unproven.

  * The Lisp and Scheme communities make a concerted effort to explain
their data model clearly and precisely.  They accept that it's
actually quite complicated and, rather than pretend that it isn't,
explain the complexity and the benefits it brings that make the
complexity worthwhile.  I think this is the likely one.


That's a nice way of putting it.  I might go a step further and say that 
there is a small but vocal portion of the Python community that insists 
on confounding the issue by claiming that Python's assignment and 
parameter-passing conventions are different from other languages. 
(Which, of course, requires one's head to be firmly in the sand with 
regard to the basic fact that Python variables contain references, not 
objects.)



But it's not just assignment that deals with references.  It's argument
passing and storage of compound data as well.  (See PLR 3.1.)

They expect that assignment copies stuff, because that's what assignment
does.  Everywhere that I can think of -- except C++, which leaves
assignment semantics in hands of the programmer.  What they're confused
about is what, precisely, it is that gets copied.  And that, really, is
a result of an inadequate understanding of the data model.


I have nothing to add to this.  It just seem well worth quoting.  :)


I agree that most of the time, when one is using large (memory)
composite objects, and one needs to pass, or access them by
different names, one will often use references to do so in order to
avoid expensive copies or to get desired shared behavior.  But (with
the exception of C arrays [*1]), doing so requires some special syntax
in all the languages I mentioned (AFAIK).


Ummm... you mentioned C, C++, `Python, Java, REALbasic, .NET'.


No, actually, that was me.  rurpy's list was something like C, FORTRAN, 
Perl, and VBA.



Well, C we've dealt with.  C++ is weird.  Python we all know, and is the
main subject of the argument.  REALbasic I don't know at all, but BASICs
traditionally represent data fairly directly (rather than via
references) so will largely be like C.


Not REALbasic.  It's a very modern language with semantics pretty much 
identical to Java.  Simple types (numbers, colors, Booleans) are stored 
directly; all other types (including strings, objects, and arrays) are 
stored on the heap and accessed via references.



.NET isn't a language at all:
rather, it's a virtual machine, runtime system, class library and family
of languages each of which may have idiosyncratic semantics.


But they don't, AFAIK -- they all have the same semantics; only the 
surface syntax differs.  And those semantics are the same as REALbasic 
and Java.


See http://www.strout.net/info/coding/valref/ for some side-by-side 
comparisons.



Which leaves Java.  Java divides the world into `primitive' and
`reference' types (4.1).  The former are represented directly; the
latter have a pointer to the true data as immediate representation.


Right -- a very common pattern among modern languages.


So it still seems to me that this is a likely explanation to why there
is frequent misunderstanding of Python's assignments, and why
responding to such misunderstandings with, Python's assignments are
the same as other languages', is at best not helpful.


That's why I'm not just saying that assignment is the same.  I'm also
saying that the data model is most definitely not the same as C.


Technically true, in that pointers in C require some special syntax, but 
the common idiom is to hide this away by defining a new type:


 typedef Foo* FooPtr;

Now, for any code using the FooPtr type, the data model is the same as 
Python (or as Java, RB, .NET, etc., again for code that's using only 
reference types).


Best,
- Joe



--

Re: why cannot assign to function call

2009-01-09 Thread rurpy
Joe Strout wrote:
 ru...@yahoo.com wrote:

 I never claimed that you *couldn't* have copy semantics in C; you can do
 almost anything you want in C (or C++).  But the *normal* usage of an
 array is via a pointer, in which case the semantics are exactly the same
 as in Python, Java, REALbasic, .NET, etc.

 Arrays are the only datatype in C that don't use
 copy-like assignment.  Everything else does.

 No, arrays are just one reference type; pointers are another (and in
 most ways, these are the same thing).

Pointers are passed and assigned by value, just as
other types (disputedly except arrays) are.
One can then use that pointer to manually effect
pass-(the-value-pointed-to)-by-reference, or sharing,
etc.

 When dealing with objects in C++,
 one routinely handles them with pointers, so that's the use case which
 is analogous to Python -- all the value types can be ignored for the
 sake of comparison.  (C is not an OOP language, of course, but even
 there, all but the most trivial of structs are usually allocated on the
 heap and passed around via pointers, just like in C++, Java, .NET, RB,
 and Python.)

In C (you have to explicitly ask for a reference
(pointer) to something (other than arrays) if you
want to use/pass a reference to something.
If you simply use the name, you get by-value semantics.

 Ah.  OK then, I guess I missed you're point.  You're absolutely right;
 many languages have both reference types and value types.  Python is a
 bit unusual in that it has only reference types.  I would have picked a
 different example to illustrate that, but it's true nonetheless.

 If one accepts that there are a lot of people
 who post in here that clearly are surprised by
 Python's assignment semantics, and further appear
 to expect assignment to have copy-like semantics,
 then where is that expectation coming from?

 I think it comes from people stumbling across posts in this forum
 claiming that Python has unusual assignment semantics.  I wish people
 would stop saying that, as it causes a lot of confusion.

 How would anyone develop that expectation if (from
 a different post in this thread), [Python's] idea
 of assignment is the same as anyone else's.

 I can think of two ways:

 1. They're new to programming in general, and would have had the same
 expectation for any other language.  OR,

IIRC, Someone posted here that his experience was
that 12-year old kids (presumably without programming
experience) had no problem with Python and references
when described as names given to an object.  (From
memory, can't locate the post right now.)

 2. They already understand some other language, and then they come here
 and read wild claims that Python's assignment and parameter-passing
 semantics are different from other languages.  Duped by this claim, they
   conclude that, if it's unlike other languages, then Python must have
 copy semantics.

I have seen no evidence of that.  If it were true I
would expect at least some posts to refer to reading
those wild claims.

 If you maintain that reference-like assignment
 is very common and something every programmer is
 accustomed to, then where are they getting the
 copy-like assignment expectations from?

 Reference-like assignment IS very common (see
 http://www.strout.net/info/coding/valref/).  So, see above.

 I agree that most of the time, when one is using
 large (memory) composite objects, and one needs
 to pass, or access them by different names, one will
 often use references to do so in order to avoid
 expensive copies or to get desired shared behavior.

 Right.

 But (with the exception of C arrays [*1]), doing so
 requires some special syntax in all the languages I
 mentioned (AFAIK).

 Whether you consider it special or not, pointers are extremely common
 in C.  Even more so in C++, which is the closest thing to an OOP
 language in the list of moldy languages you mentioned.

Non-special is b = a.

 You also mentioned VBA -- if that's anything like VB, it does NOT
 require any special syntax; a variable is a reference type if its
 declared type is a class or string, and a simple type if it's anything
 else (just like in .NET, Java, and REALbasic).

It (mercifully) been a long time since I've used
VB but the VB code I posted does run, and does exhibit
by-value assignment behavior.  My faint recollection
is that if you want to assign a reference you cannot
write, b = a but must instead write set b = a.
b = a assigns by value.

In Perl it is definitely true that you different syntax:
@a = (1,2,3)
@b = @a   # Copy
$b = \...@a  # Reference

C is the same way for everything (including pointers)
except arrays:

struct {...} foo;
foo a, b *bp;
b = a;  # Copy
bp = a; # Reference

 So it still seems to me that this is a likely
 explanation to why there is frequent misunderstanding
 of Python's assignments, and why responding to such
 misunderstandings with, Python's assignments are
 the same as other languages', is at best not helpful.

 I don't think so.  More 

Re: why cannot assign to function call

2009-01-09 Thread Benjamin Kaplan
On Fri, Jan 9, 2009 at 7:11 PM, Joe Strout j...@strout.net wrote:

 Mark Wooding wrote:


  .NET isn't a language at all:
 rather, it's a virtual machine, runtime system, class library and family
 of languages each of which may have idiosyncratic semantics.


 But they don't, AFAIK -- they all have the same semantics; only the surface
 syntax differs.  And those semantics are the same as REALbasic and Java.


They do in fact differ. You can have Visual C++ compile to CLI, in which
case you have the C++ assignment in .NET, you can use VisualBasic, in which
you can specify pass-by-value or -reference when you pass arguments to
methods, and you have Visual C#, which copies Java's model and is therefore
the same as Python.



 See http://www.strout.net/info/coding/valref/ for some side-by-side
 comparisons.

--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-09 Thread Steven D'Aprano
On Fri, 09 Jan 2009 21:03:39 +, Mark Wooding wrote:

 Steven D'Aprano st...@remove-this-cybersource.com.au wrote:
 
 Python doesn't do the same thing as C. It actually passes the same
 value to the function, without copying it.
 
 Why oh why do you keep insisting that Python is no different from C?
 
 I'm beginning to think that you're not bothing to read what I'm writing,

Er, perhaps you missed that I was replying to Joe Strout.

Joe wrote:

The reference itself is passed in, not the variable (or 
expression) that held or generated the reference in the calling code.

This is no different from, in C, passing an integer:

I'm pretty sure I clearly quoted Joe in my post. Perhaps you missed it. 
In any case, I'm happy for you to contribute (it's a public forum), but 
how do you conclude I'm not reading *your* posts because I disagree with 
Joe's claim that Python is just like C?




-- 
Steven
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-09 Thread Grant Edwards
On 2009-01-10, Joe Strout j...@strout.net wrote:
 Mark Wooding wrote:

 As an aside, I don't notice anywhere near as much confusion in Lisp and
 Scheme groups, which might be surprising since Lisp and Scheme have
 precisely the same data model, argument passing convention, and
 assignment semantics, as Python has.

 Nor is there anywhere near as much confusion in the REALbasic
 community (with which I'm most familiar), which also has the
 same semantics for reference types (which in RB is everything
 except numbers, colors, and Boolean).

It's not that there's a lot of confusion, it's just that we
spend a lot of time talking about it.  Programming in Python is
so much more productive that we've got a lot more spare time
that people who use other languages.

-- 
Grant

--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-09 Thread Rhodri James

On Sat, 10 Jan 2009 00:21:27 -, ru...@yahoo.com wrote:


Joe Strout wrote:

ru...@yahoo.com wrote:


[snip]


Pointers are passed and assigned by value, just as
other types (disputedly except arrays) are.
One can then use that pointer to manually effect
pass-(the-value-pointed-to)-by-reference, or sharing,
etc.


[snip]


In C (you have to explicitly ask for a reference
(pointer) to something (other than arrays) if you
want to use/pass a reference to something.
If you simply use the name, you get by-value semantics.



How would anyone develop that expectation if (from
a different post in this thread), [Python's] idea
of assignment is the same as anyone else's.


I can think of two ways:

1. They're new to programming in general, and would have had the same
expectation for any other language.  OR,


IIRC, Someone posted here that his experience was
that 12-year old kids (presumably without programming
experience) had no problem with Python and references
when described as names given to an object.  (From
memory, can't locate the post right now.)


'Twas I.  It was a rebuttal to your point that Python's assignment,
parameter passing and data model is somehow inherently more difficult
to wrap your brain around than that of other languages.  It isn't; if
anything it seems to be easier.


2. They already understand some other language, and then they come here
and read wild claims that Python's assignment and parameter-passing
semantics are different from other languages.  Duped by this claim, they
  conclude that, if it's unlike other languages, then Python must have
copy semantics.


I have seen no evidence of that.  If it were true I
would expect at least some posts to refer to reading
those wild claims.


3. They conflate assignment, parameter passing and the data model, bring in
preconceptions of their own from other languages, and get caught out by
them.  It's quite easy to do, even within a language.  Look at the number
of times you had to say except arrays about C above.


In Perl it is definitely true that you different syntax:
@a = (1,2,3)
@b = @a   # Copy
$b = \...@a  # Reference


Perl has different syntax for everything.  It also has its own
peculiarities of assignment and data model that make it a less than
glowing example of comprehensibility.  List flattening, for instance,
is amazingly useful in many common Perl idioms, but really not what
you expect during assignment.


C is the same way for everything (including pointers)
except arrays:


Oh look, there's that exception again.


It may be one can make a technical case that assignment
is the same, but the reason I posted the code and results,
was because the behavior of = in them produces clearly
different results that = in Python.  If you want to
then say to someone, ignore those different results,
'=' works exactly the same, all I can say is good luck.
I will look forward to continuing to see weekly questions
on this list. :-)


It would help if you were using = on things that were conceptually
the same across the languages, instead of things that only looked
similar.  Which is where the data model comes in, as has already been
explained at length, several times now.

--
Rhodri James *-* Wildebeeste Herder to the Masses
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-09 Thread Mark Wooding
Joe Strout j...@strout.net wrote:

 No, actually, that was me.  rurpy's list was something like C, FORTRAN, 
 Perl, and VBA.

My mistake -- I failed to read the quoting properly.  Apologies to all.

We still dealt with C.

Fortran (to give it its modern spelling) has a similar data model to C,
but passes arguments by reference, as described in my Epic Argument
Passing Article; I believe that arbitrary expressions may be used as
arguments, though I'm unsure as to the semantics of modifying parameters
bound to the resulting temporary argument locations.

I must confess to being ignorant of VBA.  My excuse is that I avoid
Windows systems as much as practical, and VBA doesn't have a significant
uptake on other systems.

Perl has a very strange data model indeed, and it's hard to get a proper
handle on it without getting into implementation details: unlike Python,
Perl is largely defined /by/ its implementation.

Perl has `references', which are proper (scalar) values through which
one may read and modify other values; i.e., they're what I called
`locatives' elsewhere.  Perl provides syntactic sugar, through its
`prototypes' which will convert an actual argument which designates
(e.g.) a list or hash into a reference to that list or hash; prototypes
provide other syntactic shortcuts too, though they have no fundamental
semantic effect.  In order to add to the confusion, Perl also provides
`typeglobs', which are a reification of toplevel variable bindings.

Perl's argument passing is fundamentally by /reference/.  Given the
function

  sub swap { ($_[0], $_[1]) = ($_[1], $_[0]) }

after setting $a = 1, $b = 2, and calling swap $a, $b, we find that $a
has the value 2 and $b is 1.

What's going on here is that a `location' in Perl is an explicit SV, AV
or HV object (for `scalar-', `array-' and `hash-value' respectively.
Calling a subroutine involves marking a position on a stack, pushing a
number of SVs, and then executing the subroutine's code, which receives
the items between the stack pointer and mark in the @_ array.  In the
case of argument expressions which designate SVs, those SVs are pushed
directly, and are therefore made available via @_.  Arguments which are
arrays or hashes are flattened: their components are pushed onto the
stack.  (This use of the stack corresponds to what the Perl manual
refers to as `list context'.)

 Not REALbasic.  It's a very modern language with semantics pretty much
 identical to Java.

Very well; thanks for the correction.  I might have a look at this at
some point.

  .NET isn't a language at all: rather, it's a virtual machine,
  runtime system, class library and family of languages each of which
  may have idiosyncratic semantics.
 
 But they don't, AFAIK -- they all have the same semantics; only the 
 surface syntax differs.  And those semantics are the same as REALbasic 
 and Java.

There's a .NET implementation of C++, which obviously brings all of
C++'s low-level data model (and it's user-definable assignment and
copying).  C#'s data model is more complex than Java's because it
provides mutable compound `value types', i.e., types whose immediate
representations consist of the raw contents of the object rather than a
reference.  The mutability allows one to distinguish this IR from a
reference IR.  C# is additionally complicated by its automatic boxing
and unboxing rules: an object of value type may under some circumstances
be `boxed', appearing as an object of reference type, and obeying the
reference-type semantics.

 Technically true, in that pointers in C require some special syntax, but 
 the common idiom is to hide this away by defining a new type:
 
   typedef Foo* FooPtr;
 
 Now, for any code using the FooPtr type, the data model is the same
 as Python (or as Java, RB, .NET, etc., again for code that's using
 only reference types).

This is a syntactic transformation rather than a change to the data
model, though.

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-09 Thread Mark Wooding
Steven D'Aprano st...@remove-this-cybersource.com.au wrote:

 Er, perhaps you missed that I was replying to Joe Strout.

Yes, evidently.  My apologies for the mix up!

-- [mdw], who obviously should put the keyboard down now.
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-09 Thread rurpy
Mark Wooding wrote:
 ru...@yahoo.com ru...@yahoo.com wrote:

 If one accepts that there are a lot of people who post in here that
 clearly are surprised by Python's assignment semantics,

 But one should not accept that.  One might accept that there are many
 who post who claim that they are surprised by Python's assignment
 semantics.  Such people are wrong, however, since what they are
 surprised by is Python's data model, and one reason that they are
 surprised by Python's data model is because it's not actually explained
 very well.

Agreed.  I think the docs, especially those that develop
the conceptual model of how Python work at runtime, could
use some major attention.

 and further appear to expect assignment to have copy-like semantics,

 This expectation is justified and, indeed, satisfied.  Python does, most
 definitely, copy on assignment.  What it copies is references, however.
 This might be clearer if the data model were explained better.
 ...
 then where is that expectation coming from?

 How would anyone develop that expectation if (from a different post in
 this thread), [Python's] idea of assignment is the same as anyone
 else's.

 Because they've fundamentally misunderstood the data model.  The very
 fact that their confusion is ascribed to the wrong thing is strongly
 indicative of this.

 If you maintain that reference-like assignment is very common and
 something every programmer is accustomed to, then where are they
 getting the copy-like assignment expectations from?

 But it's not just assignment that deals with references.  It's argument
 passing and storage of compound data as well.  (See PLR 3.1.)

 They expect that assignment copies stuff, because that's what assignment
 does.  Everywhere that I can think of -- except C++, which leaves
 assignment semantics in hands of the programmer.  What they're confused
 about is what, precisely, it is that gets copied.  And that, really, is
 a result of an inadequate understanding of the data model.
...
 So it still seems to me that this is a likely explanation to why there
 is frequent misunderstanding of Python's assignments, and why
 responding to such misunderstandings with, Python's assignments are
 the same as other languages', is at best not helpful.

 That's why I'm not just saying that assignment is the same.  I'm also
 saying that the data model is most definitely not the same as C.

I would be willing to bet that most of the confused
posters do not distinguish between assignment operation
(AO) and data model (DM).  Their conceptual box is
labeled assignment behavior and includes both AO and
DM.  They expect that AO+DM in Python will produce the
same results in Python as they are used to in the other
languages they've used.  That the discrepancy comes from
the DM part rather than the AO part is pretty irrelevant
to them given that world view.

So responding to the cry, Python assignment is bizarre!
with an indignant, No, it is the same as other common
languages, is talking with different vocabularies, unless
it's also accompanied with all the other information presented
in this thread about how Python treats all names as references
(which *is* different that some other languages).

I notice there is not even an FAQ on the subject of assignment
despite the frequency which which people ask about it.

 I have often wished that C handled arrays the same way it does
 structs.  I am sure that the pointer-array pseudo-equivalence seemed
 like a very clever idea at the time but I wonder if Dennis Richie ever
 had second thoughts about it.

 Probably.  But I think the idea was actually inherited from BCPL, via B.
 In BCPL, memory is divided into words.  Depending on which operator you
 use, you can treat a particular word as an integer, a floating-point
 number, or a pointer.  An array in BCPL is represented as a pointer to
 its first element -- always -- and you index it by an expression of the
 form p!i (a notation inherited by BBC BASIC and Haskell of all things).
 The array-pointer decay is a compromise position between the BCPL
 notion of array-as-pointer and the desire to allocate such things with
 automatic storage duration and have sizeof and so on work properly.

Interesting tidbit, thanks.
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-09 Thread rurpy
Rhodri James wrote:
 On Sat, 10 Jan 2009 00:21:27 -, ru...@yahoo.com wrote:
 IIRC, Someone posted here that his experience was
 that 12-year old kids (presumably without programming
 experience) had no problem with Python and references
 when described as names given to an object.  (From
 memory, can't locate the post right now.)

 'Twas I.  It was a rebuttal to your point that Python's assignment,
 parameter passing and data model is somehow inherently more difficult
 to wrap your brain around than that of other languages.  It isn't; if
 anything it seems to be easier.

That was and is not my point.  My point was that there
seems to be an observably significant number of people
who are surprised by the way Python assignment works.
I hypothesized that this was due to their experience with
other languages, *not* that Python is somehow inherently
more difficult to wrap your brain around, and that the
response, Python assignments are the same as in those
other languages is insufficient.
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-08 Thread Steven D'Aprano
On Wed, 07 Jan 2009 03:45:00 -0800, sturlamolden wrote:

 On Jan 7, 2:02 am, Steven D'Aprano
 ste...@remove.this.cybersource.com.au wrote:
 
 In Python code, there are no references and no dereferencing.
 
 The why does CPython keep track of reference counts?

Two different levels of explanation. At the level of Python code, you 
don't see reference counts. You never manipulate reference counts 
directly. The gc module does expose them, if you want to see them, but 
the gc module deliberately peaks behind the curtains. It's special.

At the implementation level, CPython uses references so it needs 
reference counts. Jython doesn't keep reference counts at all, because it 
uses Java's garbage collection (or so I understand). And the hypothetical 
Distributed Python uses clones of objects and a daemon which keeps them 
in sync, and hence there are no reference counts because each clone is 
attached once and once only. 



 You can't, because Python doesn't have references. In a language with
 references, that's easy.
 
 Python does not 'pass-by-reference' as Fortran or Pascal do.

That's right. But sadly, if you tell people that Python uses references, 
many people will say How do I pass a reference to this object to a 
function?.




 a = 123456789
 b = [a]
 c = [a]
 d = [a, a]
 
 b[0] is a
 True
 c[0] is a
 True
 d[0] is a
 True
 d[1] is a
 True
 
 Where is the object 'a' stored?

Somewhere in memory, floating free, where it is referred to under the 
name 'a'. In CPython, it will be in the heap, unless it has been paged 
out to disk.

In the lists 'b', 'c' and (twice) 'd'.

I don't have a problem with objects being in two places at the same time. 
It's just a mental model. I understand that, underneath, the memory for 
the object is in *one place*, somewhere, because distributed storage is a 
hard problem and no existing Python does it. But I also understand that 
underneath, *everything* is just mutable bytes. There are no ints or 
strings or lists or dicts, they're just an abstraction. If you keep 
looking behind the curtains, looking at the implementation of each level 
of abstraction, eventually you'll get to bytes, and then electrons. If 
you go there, then you'll conclude that the object 'a' isn't anywhere.

I'm happy with a high-level abstraction where Python objects can be in 
more than one place at once. Now, how do you implement such an 
abstraction? The easiest way is to have the object in one (hidden?) 
place, and have everywhere else use a pointer or reference to it. But 
that's a lower level of description than you can reach from Python code, 
because you can't access those pointers. You can only infer that they are 
there because otherwise you have to accept that objects can be in two 
places at once.

Or because you've read the source code, but that's implementation.


-- 
Steven
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-08 Thread Aaron Brady
On Jan 8, 1:45 am, Steven D'Aprano
ste...@remove.this.cybersource.com.au wrote:
 On Wed, 07 Jan 2009 10:17:55 +, Mark Wooding wrote:
snip
  The `they're just objects' model is very simple, but gets tied up in
  knots explaining things.  The `it's all references' model is only a
  little more complicated, but explains everything.

 But it *over* explains, because it implies things that everybody knows
 about references in other languages that aren't true for Python.

 Of course it's not literally true that everybody knows that you can use
 references to implement a swap(x, y) procedure. But people coming from a
 C or Pascal background tend to assume that everything is like C/Pascal,
 and there are a lot of them. If C was a rare, unfamiliar language, my
 opposition to using the term reference would be a lot milder. Maybe in
 another five years?

  No, indeed.  Python is a language for talking about paperweights.  And
  it's because of the paperweights that the duck-typing works: all the
  paperweights are the same shape and size, so they're physically
  interchangeable.

 Okay, the abstraction has leaked again... are the paperweights references
 to the objects, or the names we've bound objects to? I'm confused...

 How do we deal with anonymous objects in your model?

 --
 Steven

Mark, hi, Steven, pleasure as always.

Neither side is perfect or wild; (Do admit it); How do we decide what
is best for newcomers to Python, depending on background?
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-08 Thread Mark Wooding
ru...@yahoo.com ru...@yahoo.com wrote:

 I thought you were objecting to Python's use of the term binding
 when you wrote:

[snip]

 in response to someone talking about ...all those who use the term
 \name binding\ instead of variable assignment

Oh, that.  Well, the terms are `binding' and `assignment'.

Python doesn't need another name for assignment, because actually its
idea of assignment is the same as anyone else's.  The difference is in
the way it deals with objects.  See argument elsewhere.

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-08 Thread Steve Holden
Aaron Brady wrote:
 On Jan 8, 1:45 am, Steven D'Aprano
 ste...@remove.this.cybersource.com.au wrote:
 On Wed, 07 Jan 2009 10:17:55 +, Mark Wooding wrote:
 snip
 The `they're just objects' model is very simple, but gets tied up in
 knots explaining things.  The `it's all references' model is only a
 little more complicated, but explains everything.
 But it *over* explains, because it implies things that everybody knows
 about references in other languages that aren't true for Python.

 Of course it's not literally true that everybody knows that you can use
 references to implement a swap(x, y) procedure. But people coming from a
 C or Pascal background tend to assume that everything is like C/Pascal,
 and there are a lot of them. If C was a rare, unfamiliar language, my
 opposition to using the term reference would be a lot milder. Maybe in
 another five years?

 No, indeed.  Python is a language for talking about paperweights.  And
 it's because of the paperweights that the duck-typing works: all the
 paperweights are the same shape and size, so they're physically
 interchangeable.
 Okay, the abstraction has leaked again... are the paperweights references
 to the objects, or the names we've bound objects to? I'm confused...

 How do we deal with anonymous objects in your model?

 --
 Steven
 
 Mark, hi, Steven, pleasure as always.
 
 Neither side is perfect or wild; (Do admit it); How do we decide what
 is best for newcomers to Python, depending on background?

The crux of this mistake is assuming that all beginners are alike, and
that there is therefore a single best way to explain things to them.
Teaching should be a dialog, in which the teacher makes use of knowledge
revealed by the student about their existing knowledge and ways of
thinking to present ideas in an easily assimilable form.

In other words, don't treat all students the same.

regards
 Steve
-- 
Steve Holden+1 571 484 6266   +1 800 494 3119
Holden Web LLC  http://www.holdenweb.com/

--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-08 Thread Dan Esch
Absolutely.

Trivially and at a high level,

teaching python to kids who are learning programming as introductory
material

teaching python to motivated college graduate students
teaching python to adult non-professional programmers with a need to learn
python (like for instance, frustrated accountants who have HAD IT with
VBA...)

The difference between the last 2 is important.  I am not now nor will I
ever be a professional programmer; there's a depth of knowledge to the
subject that I will not ever systematically study (mostly due to time
constraints).  On the other hand, the problems I want and need to solve, I
want to get right and will put in the effort to learn what I need to get it
right.  Contrast the college student.  He's getting a broad and hopefully
deep grounding in more CS theory than I have.  How much does he care?  Well,
the beer bash Friday at 4 probably has a higher priority in his life right
now, not unreasonably.

So you can explain things to me fairly technically (I've done lots of VBA
programming, hated it, and am motivated in self-study in python), but not
too abstractly, because I don't have a deep ground in the theory behind CS
and programming. (What I know of grammar parsing comes via some linguistics
work I did in college, not Backus-Naur Form, although Noam chomsky was
important in both fields)

In contrast, the CS student should get a generalized explanation because he
needs to grow the skills to work it out on his own, and because the
generalized and theoretically grounded explanation is more useful for him in
extrapolating to other areas.  If he can't do more with it than i can, he
needs to change majors.

On 1/8/09, Steve Holden st...@holdenweb.com wrote:

 Aaron Brady wrote:
  On Jan 8, 1:45 am, Steven D'Aprano
  ste...@remove.this.cybersource.com.au wrote:
  On Wed, 07 Jan 2009 10:17:55 +, Mark Wooding wrote:
  snip
  The `they're just objects' model is very simple, but gets tied up in
  knots explaining things.  The `it's all references' model is only a
  little more complicated, but explains everything.
  But it *over* explains, because it implies things that everybody knows
  about references in other languages that aren't true for Python.
 
  Of course it's not literally true that everybody knows that you can
 use
  references to implement a swap(x, y) procedure. But people coming from a
  C or Pascal background tend to assume that everything is like C/Pascal,
  and there are a lot of them. If C was a rare, unfamiliar language, my
  opposition to using the term reference would be a lot milder. Maybe in
  another five years?
 
  No, indeed.  Python is a language for talking about paperweights.  And
  it's because of the paperweights that the duck-typing works: all the
  paperweights are the same shape and size, so they're physically
  interchangeable.
  Okay, the abstraction has leaked again... are the paperweights
 references
  to the objects, or the names we've bound objects to? I'm confused...
 
  How do we deal with anonymous objects in your model?
 
  --
  Steven
 
  Mark, hi, Steven, pleasure as always.
 
  Neither side is perfect or wild; (Do admit it); How do we decide what
  is best for newcomers to Python, depending on background?

 The crux of this mistake is assuming that all beginners are alike, and
 that there is therefore a single best way to explain things to them.
 Teaching should be a dialog, in which the teacher makes use of knowledge
 revealed by the student about their existing knowledge and ways of
 thinking to present ideas in an easily assimilable form.

 In other words, don't treat all students the same.

 regards
 Steve
 --
 Steve Holden+1 571 484 6266   +1 800 494 3119
 Holden Web LLC  http://www.holdenweb.com/

 --
 http://mail.python.org/mailman/listinfo/python-list

--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-08 Thread Mark Wooding
[Steven's message hasn't reached my server, so I'll reply to it here.
Sorry if this is confusing.]

Aaron Brady castiro...@gmail.com wrote:
 On Jan 8, 1:45 am, Steven D'Aprano
 ste...@remove.this.cybersource.com.au wrote:
  On Wed, 07 Jan 2009 10:17:55 +, Mark Wooding wrote:
 
   The `they're just objects' model is very simple, but gets tied up in
   knots explaining things.  The `it's all references' model is only a
   little more complicated, but explains everything.
 
  But it *over* explains, because it implies things that everybody knows
  about references in other languages that aren't true for Python.

I addressed this elsewhere.  Summary: `pass-by-reference' is a different
thing to `all you manipulate are references': Python does pass-by-value,
but the things it passes -- by value -- are references.

(The `pass-by-*' notions are confusingly named anyway.  Pass-by-name
doesn't actually involve names at all.)

  Of course it's not literally true that everybody knows that you
  can use references to implement a swap(x, y) procedure. But people
  coming from a C or Pascal background tend to assume that everything
  is like C/Pascal, and there are a lot of them. If C was a rare,
  unfamiliar language, my opposition to using the term reference
  would be a lot milder. Maybe in another five years?

I agree with the comment about Pascal, but C is actually pretty similar
to Python here.  C only does pass-by-value.  If you want a function to
modify your variable, you have to pass a pointer value which points to
it.  Python has no pointer values, so you need a different hack.  The
hack usually involves lists.  (Though it's easier in the main to return
compound data objects like tuples.  I don't suppose that a proposal for
true multiple return values would go down well here.  No, didn't think
so...)

  Okay, the abstraction has leaked again... are the paperweights references
  to the objects, or the names we've bound objects to? I'm confused...

They're the references to the objects.  You don't bind names to
objects.  You bind names slots in which you store references.

This discussion -- I'd call it an argument, but that might give the
wrong impression, because I think we're being remarkably civil and
constructive by the standards of Usenet arguments! -- hasn't started on
the topic of variable bindings or environments yet.

  How do we deal with anonymous objects in your model?
 
  --
  Steven
 
 Mark, hi, Steven, pleasure as always.

Hello. ;-)

 Neither side is perfect or wild; (Do admit it); 

It's true.

 How do we decide what is best for newcomers to Python, depending on
 background?

That I really don't know.  I'm not good at teaching total beginners
(does it show?) because I'm too enmired in the theory.  (It doesn't help
that I go off on tangents about how language X does something similar
but subtly different all the time, though my rich background comes in
very useful all over the place and that's something I think is worth
sharing.)

It probably doesn't help that I came to Python with a thorough
understanding of Scheme (among many others) under my belt, because many
Scheme concepts carry over directly, including the data model (it's all
references) and the variable model (nested, mutable, lexical
environments with closures).

What I am pretty sure of is that references are going to have to enter
the picture at some point, because other models get too complicated.

Oh, while I remember: the `distributed Python' model, with auto-updating
copies, only works for sharing.  Circular structures still require
actual references or a Tardis.

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-08 Thread Mark Wooding
Erik Max Francis m...@alcyone.com wrote:
 Terry Reedy wrote:

a='par'+'rot'
b='parrot'
a is b
  True
 
 One exactly doesn't really say much.  It's implementation dependent, and 
 depends on the length of the string:
 
   a = 'this is a much longer ' + 'parrot'
   b = 'this is a much longer parrot'
   a is b
 False

That Terry's example works is due to constant folding in the bytecode
compiler.  Consider:

In [1]: a = 'parrot'

In [2]: a is 'par' + 'rot'
Out[2]: True

Fair enough.  But build the string in a more complicated way:

In [3]: b = 'par'

In [4]: a is b + 'rot'
Out[4]: False

What's going on?  In the first case, the compiler notices that both
operands to `+' are constants, and evaluates the concatenation at
compile-time.  The resulting constant string is then interned if it's
short enough.

Putting part of the string in a variable is enough to stymie this
optimization -- the same compiler gets used in functions which can't
assume that the variable will still have the same value as it does now.
The concatenation method on strings doesn't try to intern the result, as
that might be a runtime performance loss.

 In practice, tests like these are pretty much never useful.  It's 
 completely implementation dependent when and under what circumstances 
 fundamental immutable objects are reused, and it's not useful anyway; 
 what you care about is whether two objects are equal or not, not whether 
 they're the same object through some optimization behind the scenes.

Absolutely.  The examples above provide insight into how the specific
implementation actually behaves; but that's of strictly academic
interest.  (Well, I find that sort of thing interesting, anyway.)

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-08 Thread Joe Strout

Mark Wooding wrote:


The `they're just objects' model is very simple, but gets tied up in
knots explaining things.  The `it's all references' model is only a
little more complicated, but explains everything.

But it *over* explains, because it implies things that everybody knows
about references in other languages that aren't true for Python.


I addressed this elsewhere.  Summary: `pass-by-reference' is a different
thing to `all you manipulate are references': Python does pass-by-value,
but the things it passes -- by value -- are references.


Quite right.  It's easy to see this in languages where some types are 
references and others are simple values; and even easier in such a 
language that supports both pass-by-value and pass-by-reference (such as 
REALbasic or VB.NET).  Then you can easily see, in one language, all 
combinations of [value type, reference type] * [pass by ref, pass by val].


In Python, we only have reference types, and we only have pass by value, 
so out of the four combinations above, there is only one: references 
passed by value.  You'd think this would make it easier, but from the 
raging debates and repeated obfuscation on this point, it apparently 
makes Python MORE difficult to understand and explain (at least for some).



I agree with the comment about Pascal, but C is actually pretty similar
to Python here.  C only does pass-by-value.  If you want a function to
modify your variable, you have to pass a pointer value which points to
it.


Right -- a C/C++ pointer is (or at least, can be in normal usage) pretty 
similar to a reference (though of course you can do more low-level and 
hackish things with them too).  In C, such a reference is always passed 
by value, as in Python or Java, and just like the default mode in RB or 
.NET.  In C++, you can also choose to pass such a parameter by 
reference, like the ByRef mode in RB and .NET.  This parameter passing 
mode is unavailable in Python or Java.



Okay, the abstraction has leaked again... are the paperweights references
to the objects, or the names we've bound objects to? I'm confused...


They're the references to the objects.  You don't bind names to
objects.  You bind names slots in which you store references.


Well put (again).  This is technically the correct description, though 
in casual usage, I think it's fine to occasionally gloss over some of 
these layers as long as everyone involved understands what is meant. 
(This is especially true when the references are to immutable objects, 
which are functionally very similar to simple values.)



How do we decide what is best for newcomers to Python, depending on
background?


That I really don't know.  I'm not good at teaching total beginners
(does it show?) because I'm too enmired in the theory. ...


FWIW, I've spent a fair amount of time teaching beginners, though not so 
much in Python yet.  But plenty of time in other languages where the 
same questions come up.  In my experience, pointing out that a variable 
of any object type contains a *reference* to that object, rather than 
the object data itself, and then illustrating with a couple of examples, 
quickly clears up any confusion.  I've never had a newbie require more 
than a couple of exchanges on this topic before they get it.  (And 
before I joined the Python community, I never even felt the need to 
actually draw a picture [1] to make it clearer.)



What I am pretty sure of is that references are going to have to enter
the picture at some point, because other models get too complicated.


I agree completely.  I can barely understand the other models myself.

Best,
- Joe

[1] http://www.strout.net/info/coding/valref/


--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-08 Thread rurpy
Mark Wooding wrote:
...
 Python doesn't need another name for assignment,

OK.

 because actually its
 idea of assignment is the same as anyone else's.  The difference is in
 the way it deals with objects.  See argument elsewhere.

the same as anyone else's only if [Python's] idea
of assignment does not include producing the same
results.

  a = array (1,2,3)
  b = a
  a[1] = 4
  print b

C, C++, VBA, Fortran, Perl:  1, 2, 3
Python:  1, 4, 3

Telling someone coming to Python from one of those
languages that Python's assignment works the same way
as those languages is confusing at best.  dealing
objects is part of assignment semantics ISTM.


--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-08 Thread rurpy
Mark Wooding wrote:
...
 I agree with the comment about Pascal, but C is actually pretty similar
 to Python here.  C only does pass-by-value.

As a side comment (because it always bugs me when
I read this, even though I read it in very authoritative
sources), ISTM that C passes everything by value except
arrays; they are passed by reference (by passing a
pointer to the array by value.)  Admittedly, the close
relationship between arrays and pointers makes it easy
conflate them.
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-08 Thread Joe Strout

ru...@yahoo.com wrote:


the same as anyone else's only if [Python's] idea
of assignment does not include producing the same
results.

  a = array (1,2,3)
  b = a
  a[1] = 4
  print b

C, C++, VBA, Fortran, Perl:  1, 2, 3
Python:  1, 4, 3


You are mistaken (except perhaps in the Fortran case, which is an 
oddball by modern standards, and I don't know Perl well enough to judge).


C/C++ code:

 int* a = malloc(3);
 a[0] = 1;
 a[1] = 2;
 a[2] = 3;
 int* b = a;
 a[1] = 4;
 print_array(b)
 --- Result: 1, 4, 3

REALbasic code:

 Dim a() As Integer = Array(1,2,3)
 Dim b() As Integer = a
 a(1) = 4
 PrintArray b
 -- Result: 1, 4, 3

VB.NET code would be very similar in syntax, and identical in behavior, 
to the REALbasic code.  Java would also have the same semantics, though 
my Java is too rusty to get the syntax right without actually trying it.


If you can find a language where an array variable is NOT a reference 
(and thus does not behave exactly as in Python, Java, REALbasic, C++, 
etc.), then that language is either a dinosaur or some weird academic 
oddity.


Best,
- Joe


--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-08 Thread rurpy
Joe Strout wrote:
 ru...@yahoo.com wrote:

 the same as anyone else's only if [Python's] idea
 of assignment does not include producing the same
 results.

   a = array (1,2,3)
   b = a
   a[1] = 4
   print b

 C, C++, VBA, Fortran, Perl:  1, 2, 3
 Python:  1, 4, 3

 You are mistaken

I don't think so.
See http://groups.google.com/group/comp.lang.python/msg/f99d5a0d8f869b96
The code I quoted there was tested.
In the C/C++ case, array-to-pointer coercion confuses
the issue so I embedded the array in a struct which
is more like an object.  The assignment semantics are
copy-like producing the results I quoted.  (Keep in mind
my point was not to show the behavior of arrays, but to
show that several common languages *do not* use Python's
*all* names are references model -- though of course
this does not preclude their having some Python-like
assignments since they all have some way of doing
references.)  It seems plausible to me that experience
with copy-like assignments semantics in other languages
accounts for the frequent misunderstanding of Python
assignments that is seen on this list.

 (except perhaps in the Fortran case, which is an
 oddball by modern standards, and I don't know Perl well enough to judge).

Whether or not Perl is oddball or modern is irrelevant;
it is still widely used and it is reasonable to assume
that there are a significant number of people coming
to Python with a lot of previous experience with Perl.
Even Fortran is still used in scientific computing circles
(or so I'm told) although I can't say I have seen any
c.l.p. postings from people claiming Python doesn't work
like fortran. :-)

 C/C++ code:

   int* a = malloc(3);
   a[0] = 1;
   a[1] = 2;
   a[2] = 3;
   int* b = a;
   a[1] = 4;
   print_array(b)
   --- Result: 1, 4, 3

 REALbasic code:

   Dim a() As Integer = Array(1,2,3)
   Dim b() As Integer = a
   a(1) = 4
   PrintArray b
   -- Result: 1, 4, 3

 VB.NET code would be very similar in syntax, and identical in behavior,
 to the REALbasic code.

Don't know about RealBasic or VB.Net, my experience
and quoted results were from MS Visual Basic for Apps
which is (I think) based on VB6.

--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-07 Thread Hendrik van Rooyen
Mark Wooding m.@distorted.org.uk wrote:

 A better analogy.  The objects are scattered across the floor.  No
 object is contained in another.  However, we have a plentiful supply of
 bits of string, each of which is tied to a Teflon-covered paperweight at
 one end and has a blob of Blu-Tack on the other.  Instead of putting
 something in a box directly, what we do is grab a piece of string, stick
 the Blu-Tack to the thing, and put the paperweight in the box.  This
 way, we can stick several bits of string to the same object and put the
 paperweights in different boxes.  Indeed, nothing stops us sticking two
 bits of string to a box, and putting both paperweights inside that same
 box.  But fitting a box into itself twice requires origami skills that
 frighten me.
 
 The Teflon stops the Blu-Tack from sticking to the paperweights, 'cos
 you're not allowed to do that.  
 
 There's a daemon who comes around periodically and cleans up the mess of
 paperweights which aren't in boxes, and tidies away things which don't
 have any string stuck to them any more, but really he's just an
 implementation detail and you wouldn't need him if your floor was big
 enough and you had enough bits of sufficiently long string.
 

Lovely!

This is the nicest analogy I have seen,
and it seems to completely account
for all the observed effects.

The only other one that comes close
is Dennis L Bieber's Wandering Names.

I propose that we name the garbage
collection demon Steven because
he has IMO lost this argument, and
therefore deserves to spend eternity
tied up in string.

;-)

- Hendrik

-- 
With the disappearance of the gas mantle and the advent
of the short circuit, man's tranquillity began to be threatened
by everything he put his hand on.
(James Thurber.  First sentence of Sex ex Machina)




--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-07 Thread Steven D'Aprano
On Wed, 07 Jan 2009 03:49:02 +, Mark Wooding wrote:

 Steven D'Aprano ste...@remove.this.cybersource.com.au wrote:
 
 The only tricky thing is that items 1, 2 and 3 can be inside two
 different boxes at the same time. There's no obvious real world analogy
 to that without the boxes being nested. This ability for objects to be
 in two places at once (or even to be inside themselves!) is one of the
 few reasons why Python's use of references in the implementation needs
 to be mentioned.
 
 Ahh.  So it /does/ need to be mentioned after all.  

Only in the sense that the behaviour of *real world* objects don't 
entirely match the behaviour of Python objects. If you just accept that 
Python objects can be in two places at once, an unintuitive concept I 
accept but hardly difficult to grasp, then you don't need to mention 
references.

(Of course, as a purely practical matter, the English language makes it 
difficult to avoid the word reference entirely. That's not my 
intention.)



 But you're wrong:
 it's not an implementation detail: it's an essential part of the
 language semantics.

Er, pardon me, but you yourself suggested that one could implement Python 
without using references to objects, like keeping lists of clones, and 
magically updating all the clones whenever one us mutated.  That may even 
be a valid implementation for a distributed Python.

Like you suggested, it would be a seriously rotten model for standard 
Python, but it is possible. The language semantics specifies the 
*behaviour*, not the *mechanism* required to implement that behaviour.



 A better analogy.  The objects are scattered across the floor.  No
 object is contained in another.  However, we have a plentiful supply of
 bits of string, each of which is tied to a Teflon-covered paperweight at
 one end and has a blob of Blu-Tack on the other.  Instead of putting
 something in a box directly, what we do is grab a piece of string, stick
 the Blu-Tack to the thing, and put the paperweight in the box.

Not a bad analogy. I like it. But it still fails.

Why can't I stick the paperweight in the box *before* attaching the Blu-
Tack to something else, and then forget about attaching the Blu-Tack? 
There's nothing in your model to prevent dangling pointers, except hand-
waving it doesn't work like that.

I assume the string is made of Teflon, otherwise I could stick the Blu-
Tack to another piece of string. By the same token, the floor needs to be 
Teflon too.

Why can't I grab the string by the end with the Blu-Tack and follow it 
backwards to find out where the paperweight is? I obviously know how to 
handle the end, because according to your model I'm sticking it to other 
objects. I suppose maybe there's a robot that does that Blu-Tack sticking 
for me, I just point to the object and say That one! and it happens. 
The string itself is invisible except to radar, which the robot has, and 
I don't. That way I can't follow the string backwards to find out where 
the paperweight is. Hmmm. This model is getting awfully complicated: 
Teflon string, Teflon paperweights, Blu-Tack, *and* a robot (presumably 
Teflon as well), none of which are visible to Python code, as well as 
objects which are.



 This
 way, we can stick several bits of string to the same object and put the
 paperweights in different boxes.  Indeed, nothing stops us sticking two
 bits of string to a box, and putting both paperweights inside that same
 box.  But fitting a box into itself twice requires origami skills that
 frighten me.

Ah, you've obviously never studied origami under Sensei Ping of the Clan 
of the Pointed Stick!


 The Teflon stops the Blu-Tack from sticking to the paperweights, 'cos
 you're not allowed to do that.
 
 There's a daemon who comes around periodically and cleans up the mess of
 paperweights which aren't in boxes, and tidies away things which don't
 have any string stuck to them any more,

So there's a brief moment between creating the object and sticking the 
Blu-Tack on it when the daemon might take the object and the string away? 
No, I guess not, that's another thing I just have to take on faith... the 
daemon knows not to touch anything until the robot has finished with it. 

Can I tie two pieces of string together, stop the daemon from disposing 
of them? Apparently not.

Objects in two places at one time isn't sounding that weird any more.

I actually do like your model, despite poking holes in it. As a model for 
what CPython is doing under the hood, it pretty good.

But it's not a model for what a Python programmer does when writing 
Python code. There's no action equivalent to attach blob of Blu-Tack to 
object, no action equivalent to put the paperweight in the box. The 
robot does that when you point to an object and say put that inside the 
box. The programmer doesn't do these things, he says put that object in 
the box and the robot attaches the Blu-Tack and moves the paperweight. 
The strings and paperweights and Blu-Tack are 

Re: why cannot assign to function call

2009-01-07 Thread Mark Wooding
Steven D'Aprano ste...@remove.this.cybersource.com.au wrote:

 Only in the sense that the behaviour of *real world* objects don't
 entirely match the behaviour of Python objects. If you just accept
 that Python objects can be in two places at once, an unintuitive
 concept I accept but hardly difficult to grasp, then you don't need to
 mention references.

To my mind, explaining that objects can actually be in two (or three, or
any unbounded number) of places at once, stashed inside each other to an
arbitrary degree -- that looks like the excuses of someone who's been
caught in a lie.  Maybe it was a useful lie-to-children, meant to avoid
explaining the full details in advance, but the time comes to put away
childish things, and learn the truth.  (I can't believe I just quoted
Paul.  I feel all dirty.)

 Er, pardon me, but you yourself suggested that one could implement
 Python without using references to objects, like keeping lists of
 clones, and magically updating all the clones whenever one us mutated.
 That may even be a valid implementation for a distributed Python.

 Like you suggested, it would be a seriously rotten model for standard
 Python, but it is possible. The language semantics specifies the
 *behaviour*, not the *mechanism* required to implement that behaviour.

Yes, there's an isomorphism between the two, so technically either could
be used as a model to explain the behaviour of Python.  But, to my mind
at least, the idea of references (or sticky bits of string) is the
simpler -- it doesn't involve doing anything`magically' -- so Occam
suggests that it's superior.  I'm sure, if I tried, I could come with an
even more absurd model, or express it in more complicated ways, but the
power of a model lies in its combination of simplicity and explanatory
power.

The `they're just objects' model is very simple, but gets tied up in
knots explaining things.  The `it's all references' model is only a
little more complicated, but explains everything.

It might be -- and I don't know, because I'm not an educator -- that the
`they're just objects' model hits a local maximum in the tradeoff
between simplicity and explanation that's sufficiently high that it's
useful for teaching beginners.  It's hard to expose this simple model's
weaknesses without assignment (or messing with `is' or `id');
unfortunately, it's very easy to explose them once you do have
assignment (or any kind of mutable state).  And Python's purely
functional subset is rarely used exclusively in nontrivial programs.  So
I'm sceptical that this particular lie-to-children doesn't cause more
harm than good.

 Why can't I stick the paperweight in the box *before* attaching the Blu-
 Tack to something else, and then forget about attaching the Blu-Tack? 
 There's nothing in your model to prevent dangling pointers, except hand-
 waving it doesn't work like that.

Perils of posting at half past three in the morning, I'm afraid.  I
seemed to have hit a creative streak, but my clarity of thinking was
definitely impaired.

You are only allowed to handle paperweights.  A robot does the rest.
Some of the objects might give you splinters or paper cuts.  The robot
is concerned about your safety and won't let you go near them.  There's
a wall between you and the playpen, with a catflap in it.  The robot
will fit through the catflap but you're too big.

(For advanced users only: there might be a secret hatch which lets you
into the main arena where the robot works, via a storeroom containing a
surprising quantity of handy power tools, heavy weaponry, and
explosives, but oddly lacking in safety goggles.  You can build some
truly marvellous things by sneaking through here, and persuade the robot
to do things it wouldn't usually by threatening it at gunpoint, but you
can also blow yourself up.)

You tell the robot what you want him to do by handing him paperweights.
He doesn't take the paperweights away with him, but instead hooks onto
the string so that he can follow it to the other end.  He's quite good
at following even tangled strings, and at finding paperweights in boxes
and hooking onto their strings too.  The robot will stick new strings
onto objects at your request and hand you the paperweights.

 I assume the string is made of Teflon, otherwise I could stick the Blu-
 Tack to another piece of string. By the same token, the floor needs to be 
 Teflon too.

You could do, if you were actually given a loose piece of string.  But
you aren't, so that's OK.  I was wrong that the paperweights needed to
be Teflon.

 Why can't I grab the string by the end with the Blu-Tack and follow it 
 backwards to find out where the paperweight is? 

Because you're never at that end.  And the robot just won't do that.

(The daemon in the MIT Scheme environment /can/ do this for you.  It
uses a feature called `wabbit hunting'.  You set up a `Fudd thunk'
describing which objects you want it to find the paperweights of, and
set the thing to `wabbit season'.  The daemon 

Re: why cannot assign to function call

2009-01-07 Thread sturlamolden
On Jan 7, 2:02 am, Steven D'Aprano
ste...@remove.this.cybersource.com.au wrote:

 In Python code, there are no references and no dereferencing.

The why does CPython keep track of reference counts?


 You can't, because Python doesn't have references. In a language with
 references, that's easy.

Python does not 'pass-by-reference' as Fortran or Pascal do.


 It's harder (impossible?) to write a version that will operate on
 arbitrary types, but that's statically typed languages for you.

In Python an assignment (re)binds the name to another value. You can
certainly write a swap method for mutable types. But you cannot use
the assignment operator to swap the values.


 No no no, lists and tuples store *objects*.


 a = 123456789
 b = [a]
 c = [a]
 d = [a, a]

 b[0] is a
True
 c[0] is a
True
 d[0] is a
True
 d[1] is a
True

Where is the object 'a' stored?





--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-07 Thread Marc 'BlackJack' Rintsch
On Wed, 07 Jan 2009 03:45:00 -0800, sturlamolden wrote:

 On Jan 7, 2:02 am, Steven D'Aprano
 ste...@remove.this.cybersource.com.au wrote:
 
 In Python code, there are no references and no dereferencing.
 
 The why does CPython keep track of reference counts?

Show me the *Python* code that does that.  Using reference counting for 
memory management is an implementation detail.  It's possible to use 
other garbage collectors without the need of reference counting.

Ciao,
Marc 'BlackJack' Rintsch
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-07 Thread Dan Esch
Wait a sec...

I think I get this...

In essence, the implication of immutability for Python is that there is only
one parrot, one spam,in fact one anything. (This seems like it must hold
for data primitives - does it hold for complex objects as well? It seems it
must...) In addition there is only one 1, and one 2 etc.  We may or may not
have realized that string in a memory address to which variable names can be
bound, but should we do so, there is only one parrot

Python, is in fact, a Platonic programming language.  Weird.  If I've got
this right, worth chewing on


On 1/2/09, Derek Martin c...@pizzashack.org wrote:

 On Tue, Dec 30, 2008 at 02:21:29PM +, John O'Hagan wrote:
  Fortunately, unlike the murky world of philosophy, Python (AIUI)
  simplifies this question by simply declaring that yes, in the case
  of mutable objects, we may say that we are still referring to the
  same object although we've changed it, and no, in the case of
  immutable objects, we may not, and must exchange it if we want a
  different value (a word too fraught with ambiguity in this context
  to use unquoted!).

 That's sort of true; it would seem to be more accurate to say that
 whenever a name is assigned to an object and subsequently reassigned,
 the name no longer is associated with the original object.  In the
 case of mutable objects, the object can be changed by performing an
 assignment of *part* of the object through its original name, i.e.
 strings may be mutable, but the following code still produces two
 different objects:

 a = 'hello'
 a = 'goodbye'

 The first object so created is orphaned; it's been given the Russian
 non-person treatment.  It still exists, but the authorities (i.e. the
 python interpreter) don't acknowledge it and provide the rest of the
 world no way to communicate with it, and eventually it is reaped by
 the garbage collector. :)

 What the Python community often overlooks, when this discussion again
 rears its ugly head (as it seems to every other hour or so), is that
 its assignment model is BIZARRE, as in it's conceptually different
 from virtually all other languages substantially taught in
 undergraduate computer science programs.  And for that matter, it's
 pretty unintuitive generally.

 That is, in what I'll call normal computer languages, a variable
 name is thought of as the address of a bin where some data is stored,
 and the name is inexorably tied to that bin.  You can change what's in
 the bin, but the name you gave the bin always points to the same bin.
 This tends to be conceptually true even if it might technically not be
 true in a given implementation of a language.

 Python is very different from this.  Names are not addresses of bins;
 they are instead simply ephemeral labels which are given to bins,
 where the bin is a Python object which contains specific data at the
 time of assignment.  A second assignment of that name doesn't change
 what's in the original bin; it actually (probably) first creates a new
 bin, then removes the name from the original bin and assigns it to
 the new one.  Intuitively, it's a bit like saying your kitchen table
 is no longer a kitchen table, and now the thing where you wash your
 dishes is a kitchen table.  It doesn't really make a lot of sense
 (whether or not it's so for good reason), and it makes describing the
 assignment model necessarily convoluted, whereas the named bins
 model from the majority of other languages people are likely to have
 been exposed to is simple and sensible.

 It's small wonder that neophytes try to cram Python behaviors into
 terms and computing concepts they already understand from learning
 other languages, and that they fail to do so.  What's mystifying is
 that when Pythonistas reply to their messages, they universally seem
 confused at how this could possibly happen, and often enough actually
 seem offended (or at least offensive) when it inevitably does happen...

 --
 Derek D. Martin
 http://www.pizzashack.org/
 GPG Key ID: 0x81CFE75D


 --
 http://mail.python.org/mailman/listinfo/python-list



--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-07 Thread Steve Holden
Dan Esch wrote:
 Wait a sec...
  
 I think I get this...
  
 In essence, the implication of immutability for Python is that there is
 only one parrot, one spam,in fact one anything. (This seems like it
 must hold for data primitives - does it hold for complex objects as
 well? It seems it must...) In addition there is only one 1, and one 2
 etc.  We may or may not have realized that string in a memory address to
 which variable names can be bound, but should we do so, there is only
 one parrot
  
 Python, is in fact, a Platonic programming language.  Weird.  If I've
 got this right, worth chewing on
 
'Fraid not. Certain immutables are cached by the interpreter, but most
are not.

 s1 = a + b + c
 n = 12345
 s2 = ab + chr(99)
 m = 2469 * 5
 s1 == s2
True
 s1 is s2
False
 n == m
True
 n is m
False
 id(s1), id(s2), id(n), id(m)
(2146661888, 2146661792, 14453620, 14453584)


regards
 Steve
-- 
Steve Holden+1 571 484 6266   +1 800 494 3119
Holden Web LLC  http://www.holdenweb.com/

--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-07 Thread Dan Esch
Okay, thanks...

Still trying to wrap my fragile little VBA-corrupted brain around names,
namespaces,  and objects.  Progress is being made.

For me, the naive idea of variable == label for bin has been hard to
get past simply because someone in the the back of my head is screaming,
Wait, if the VARIABLE doesn't point to a memory address, (somewhere down
the implementation stack) whatinthehell does??

Further reading clarifies:  For object X, id(X) is an immutable attribute
reference that can ultimately be bound to a memory address (he said,
blithely skipping over several layers of architecture...)  So, okay, now I
can relax.

To oversimplify (told you VBA warped my mind) everything in python is an
object (at some level).  At minimum, all objects have an identity-- id(X), a
type which subclasses and extends it from object, and some content, the
nature of which depends on the object type.

Once I got my head around the idea that there was something that was a fixed
point of reference for the object, nevermind what, then I could relax and
get on with get on with getting my head around names and namespaces.

Thanks for listening to me ramble.



On 1/7/09, Steve Holden st...@holdenweb.com wrote:

 Dan Esch wrote:
  Wait a sec...
 
  I think I get this...
 
  In essence, the implication of immutability for Python is that there is
  only one parrot, one spam,in fact one anything. (This seems like it
  must hold for data primitives - does it hold for complex objects as
  well? It seems it must...) In addition there is only one 1, and one 2
  etc.  We may or may not have realized that string in a memory address to
  which variable names can be bound, but should we do so, there is only
  one parrot
 
  Python, is in fact, a Platonic programming language.  Weird.  If I've
  got this right, worth chewing on
 
 'Fraid not. Certain immutables are cached by the interpreter, but most
 are not.

  s1 = a + b + c
  n = 12345
  s2 = ab + chr(99)
  m = 2469 * 5
  s1 == s2
 True
  s1 is s2
 False
  n == m
 True
  n is m
 False
  id(s1), id(s2), id(n), id(m)
 (2146661888, 2146661792, 14453620, 14453584)
 

 regards
 Steve
 --
 Steve Holden+1 571 484 6266   +1 800 494 3119
 Holden Web LLC  http://www.holdenweb.com/

 --
 http://mail.python.org/mailman/listinfo/python-list

--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-07 Thread rurpy
On Jan 6, 9:20 pm, Mark Wooding m...@distorted.org.uk wrote:
 ru...@yahoo.com ru...@yahoo.com wrote:
  Is not the proper term aliasing?  Perhaps Python variables should
  be called alises.

 No.  The proper term is most definitely `binding': see SICP, for
 example.  (Wikipedia has a link to the full text.)

I thought you were objecting to Python's use of the term binding
when you wrote:

 Unfortunately, this practice causes other confusion, since `binding' is
 often used (in other language communities, notably Lisp and the
 functional languages) to describe the association between names and
 slots that hold references.

in response to someone talking about ...all those who use the term
\name binding\ instead of variable assignment

--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-07 Thread Joe Strout

Dan Esch wrote:

In essence, the implication of immutability for Python is that there is 
only one parrot, one spam,in fact one anything. (This seems like it 
must hold for data primitives - does it hold for complex objects as 
well? It seems it must...) In addition there is only one 1, and one 2 
etc.


That's not necessarily true.  If you have

  a = par + rot
  b = parrot

then, most likely (though it depends on how clever the compiler 
optimizations are), there are two different string objects containing 
the data parrot.  In this case, a == b is true because string 
equality testing compares the data, but a is b is false because a and 
b refer to different objects.


And by the way, don't let the people claiming that Python's assignment 
model is bizarre confuse you.  Assignment and parameter-passing in 
Python is exactly the same as in any other modern OOP language; it just 
so happens that in Python, all variables are references, while in most 
other languages, some variables are references and others are primitive 
types.  But it should be obvious (though apparently isn't, to some) that 
this restricted, uniform data model does not fundamentally change 
anything; it just makes Python a little more restricted and uniform. 
For details, see: http://www.strout.net/info/coding/valref/


Best,
- Joe


--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-07 Thread Terry Reedy

Joe Strout wrote:


That's not necessarily true.  If you have

  a = par + rot
  b = parrot

then, most likely (though it depends on how clever the compiler 
optimizations are), there are two different string objects containing 
the data parrot.


 a='par'+'rot'
 b='parrot'
 a is b
True

--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-07 Thread rurpy
On Jan 5, 12:21 pm, Derek Martin c...@pizzashack.org wrote:
...
 I understand why the assignment model works the way it does, and it's
 quite sensible, *when you understand it*.  However, I do also think
 that to someone who has not encountered such a model before, and who
 has not had it explained to them, and/or who has not the background to
 understand why it is implemented that way, it very likely might seem
 markedly unusual in appearance, style, or general character and often
 involving incongruous or unexpected elements; as dictionary.com
 defines the term bizarre.  So no, I don't think that's a
 mischaracterization at all.
...

Ignoring the nit-picking over choice of words, or what
languages are taught in CS courses, I agree with Derek's
general point that Python's assignment semantics is *not*
the same as many other common languages, and that this
confuses people coming to Python from those languages,
as evidenced by frequent postings to this list by those
people.  I concluded exactly the same a long time ago.

When I started using Python I had no problem with Python's
assignment semantics because I had been using references in
Perl for years.  I did not have a very hard time with Perl's
references, after I recognized their similarities to C's
pointers.  But as I recall, it took a *long* time to wrap
my mind around C pointers.

Here is the output of set of equivalent programs in five
common (at least at one time) languages (code below) that I
have worked in and that formed my intuition about how
assignment works.

Sure looks to me as though Python is the odd man out.

Perl:
1, 4, 3
1, 2, 3

Basic (MS VBA):
 1 4 3
 1 2 3

C:
1, 4, 3
1, 2, 3

Fortran:
   1   4   3
   1   2   3

Python:
[1, 4, 3]
[1, 4, 3]

Of course, one can dismiss these as non-mainstream or
non-modern languages, and maintain that all important
languages have the same assignment semantics as Python,
but then one is left having to explain the frequent
confusion about assignment that is visible on this list.
I find Derek's explantion more plausible than any others
I have read in this thread.


Python:
#/usr/bin/python
a = [1,2,3]
b = a
a[1] = 4
print a
print b


Perl:
#!/usr/bin/perl
@a = (1,2,3);
@b = @a;
$a[1] = 4;
print join (',', @a), \n;
print join (',', @b), \n;


Basic:
Sub test()
Dim a, b
a = Array(1, 2, 3)
b = a
a(1) = 4
Debug.Print a(0), a(1), a(2)
Debug.Print b(0), b(1), b(2)
End Sub


C:
#include stdio.h
main () {
int i; struct {int a[3];} a, b;
for (i=0; i3; i++) {
a.a[i] = i+1; }
b = a;
a.a[1] = 4;
printf (%i,%i,%i\n, a.a[0], a.a[1], a.a[2]);
printf (%i,%i,%i\n, b.a[0], b.a[1], b.a[2]);
}

==
Fortran:
  program test
  integer a(3), b(3)
  do 100, i=1,3
  a(i) = i
100   continue
  b = a
  a(2) = 4
  write(unit=*,fmt=*) a
  write(unit=*,fmt=*) b
  end
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-07 Thread Erik Max Francis

Terry Reedy wrote:

Joe Strout wrote:


That's not necessarily true.  If you have

  a = par + rot
  b = parrot

then, most likely (though it depends on how clever the compiler 
optimizations are), there are two different string objects containing 
the data parrot.


  a='par'+'rot'
  b='parrot'
  a is b
True


One exactly doesn't really say much.  It's implementation dependent, and 
depends on the length of the string:


 a = 'this is a much longer ' + 'parrot'
 b = 'this is a much longer parrot'
 a is b
False

In practice, tests like these are pretty much never useful.  It's 
completely implementation dependent when and under what circumstances 
fundamental immutable objects are reused, and it's not useful anyway; 
what you care about is whether two objects are equal or not, not whether 
they're the same object through some optimization behind the scenes.


--
Erik Max Francis  m...@alcyone.com  http://www.alcyone.com/max/
 San Jose, CA, USA  37 18 N 121 57 W  AIM, Y!M erikmaxfrancis
  All delays are dangerous in war.
   -- John Dryden, 1631-1700
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-07 Thread Benjamin Kaplan
On Wed, Jan 7, 2009 at 7:22 PM, Terry Reedy tjre...@udel.edu wrote:

 Joe Strout wrote:

  That's not necessarily true.  If you have

  a = par + rot
  b = parrot

 then, most likely (though it depends on how clever the compiler
 optimizations are), there are two different string objects containing the
 data parrot.


  a='par'+'rot'
  b='parrot'
  a is b
 True


(this is on Mono. I don't know if the real .NET and/or newer versions of
IronPython do this differently)

IronPython 1.1 (1.1) on .NET 2.0.50727.42
Copyright (c) Microsoft Corporation. All rights reserved.
 a = par + rot
 b=parrot
 a is b
False



 --
 http://mail.python.org/mailman/listinfo/python-list

--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-07 Thread Rhodri James

On Thu, 08 Jan 2009 00:45:06 -, ru...@yahoo.com wrote:


When I started using Python I had no problem with Python's
assignment semantics because I had been using references in
Perl for years.  I did not have a very hard time with Perl's
references, after I recognized their similarities to C's
pointers.  But as I recall, it took a *long* time to wrap
my mind around C pointers.


I'd suggest that part of the reason for that is C's blurring
of the line between arrays and pointers.  You can treat them
interchangeably enough of the time that when you can't it
catches you by surprise.

My experience of teaching twelve-year olds Python is that
they understand assignment when it's explained in terms of
giving names to these objects (numbers, strings, wombats...)
that we've already shown them.  It's a lot harder to get
them to understand the putting an object into a labelled
box model when working with other languages.  I don't know
why this should be, but it is.

--
Rhodri James *-* Wildebeeste Herder to the Masses
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-07 Thread Terry Reedy

Rhodri James wrote:

On Thu, 08 Jan 2009 00:45:06 -, ru...@yahoo.com wrote:


When I started using Python I had no problem with Python's
assignment semantics because I had been using references in
Perl for years.  I did not have a very hard time with Perl's
references, after I recognized their similarities to C's
pointers.  But as I recall, it took a *long* time to wrap
my mind around C pointers.


I'd suggest that part of the reason for that is C's blurring
of the line between arrays and pointers.  You can treat them
interchangeably enough of the time that when you can't it
catches you by surprise.

My experience of teaching twelve-year olds Python is that
they understand assignment when it's explained in terms of
giving names to these objects (numbers, strings, wombats...)
that we've already shown them.  It's a lot harder to get
them to understand the putting an object into a labelled
box model when working with other languages.  I don't know
why this should be, but it is.


Kids have little experience with being 'the guest in Room 203' or 'the 
inmate in cell a-23'.


--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-07 Thread Steven D'Aprano
On Wed, 07 Jan 2009 10:17:55 +, Mark Wooding wrote:

 Steven D'Aprano ste...@remove.this.cybersource.com.au wrote:
 
 Only in the sense that the behaviour of *real world* objects don't
 entirely match the behaviour of Python objects. If you just accept that
 Python objects can be in two places at once, an unintuitive concept I
 accept but hardly difficult to grasp, then you don't need to mention
 references.
 
 To my mind, explaining that objects can actually be in two (or three, or
 any unbounded number) of places at once, stashed inside each other to an
 arbitrary degree -- that looks like the excuses of someone who's been
 caught in a lie.  Maybe it was a useful lie-to-children, meant to avoid
 explaining the full details in advance, but the time comes to put away
 childish things, and learn the truth.  (I can't believe I just quoted
 Paul.  I feel all dirty.)

All analogies are lies-to-children. I don't think this is any worse than 
the lie-to-children about magic pieces of string that you can only handle 
by the paperweight at one end. Both analogies contain leaky abstractions.


 The `they're just objects' model is very simple, but gets tied up in
 knots explaining things.  The `it's all references' model is only a
 little more complicated, but explains everything.

But it *over* explains, because it implies things that everybody knows 
about references in other languages that aren't true for Python. 

Of course it's not literally true that everybody knows that you can use 
references to implement a swap(x, y) procedure. But people coming from a 
C or Pascal background tend to assume that everything is like C/Pascal, 
and there are a lot of them. If C was a rare, unfamiliar language, my 
opposition to using the term reference would be a lot milder. Maybe in 
another five years?


 No, indeed.  Python is a language for talking about paperweights.  And
 it's because of the paperweights that the duck-typing works: all the
 paperweights are the same shape and size, so they're physically
 interchangeable.

Okay, the abstraction has leaked again... are the paperweights references 
to the objects, or the names we've bound objects to? I'm confused...

How do we deal with anonymous objects in your model?




-- 
Steven
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-06 Thread Mark Wooding
Steven D'Aprano ste...@remove.this.cybersource.com.au wrote:

 By all means, if Derek doesn't like the assignment model used by Python 
 (and Java, Ruby, C#, Perl, RealBasic, VisualBasic, Lua, and many other 
 languages going back to at least CLU in the mid 1970s) 

It goes back to Lisp in the late 1950s.

[snip stuff I agree with.]

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-06 Thread Mark Wooding
Steven D'Aprano st...@remove-this-cybersource.com.au wrote:

 (3) Those who come from an entirely different programming model, say, 
 Forth or Haskell. For them, Python's assignment model is going to be the 
 least of their worries.

Actually, Haskell's assignment model (you have to grubbing about for
IORefs or STRefs to find it but it's there) is exactly the same as Lisp,
Scheme, Python, Dylan, Perl, Lua, Icon, Ruby, Erlang, ML, ...

The variables-and-containers-hold-references-to-objects idea is common
to a very large number (probably the majority? depends how you count) of
high-level languages.

Java is in the same category.  C# is definitely not, since `struct's are
composite, mutable value types clearly distinguishable from anything
Python can do.

The main dissent is probably from Tcl, which pretends to copy values
-- even complex objects such as lists -- wholesale (though actually does
fancy copy-on-write things under the covers).

 Your first post in this topic made the extraordinarily arrogant and 
 incorrect claim that:
 
 [quote]
 What the Python community often overlooks, when this discussion again
 rears its ugly head (as it seems to every other hour or so), is that
 its assignment model is BIZARRE, as in it's conceptually different
 from virtually all other languages substantially taught in
 undergraduate computer science programs.
 [end quote]
 
 We can see some pretty poor assumptions right there:
 
 * That the Python community is capable of uniformly overlooking Python's 
 differences from other languages.
 
 * That only languages substantially taught in undergraduate CS courses 
 matter.

And a massive assumption about the languages taught to CS undergrads
too.  In particular, Scheme is a fairly popular language to teach to
undergrads, often as a first language.  See, for example, `The Structure
and Interpretation of Computer Programs' by Abelson and Sussman, and the
(much more recent) `How to Design Programs' by Felleisen, Findler, Flatt
and Krishnamurthi.

 It seems that you don't include in the Python community all those who
 use the term name binding instead of variable assignment
 specifically because it gives new users a clue that Python is not the
 same as C.

Unfortunately, this practice causes other confusion, since `binding' is
often used (in other language communities, notably Lisp and the
functional languages) to describe the association between names and
slots that hold references.

Let me explain.  I'll try to be clear, though I know that Stephen
already understands this stuff well.

At run-time, each named variable denotes a storage area (I'll call it a
slot[2]) which holds a reference to some object[1].

  +-+
   name  | ref - object   
  +-+

If we `assign' a different object to the variable, what really happens
is that the slot is modified to refer to the other object; but the name
continues to denote the same slot.

Usually `binding', or `rebinding', a name describes a different process,
whereby the name (for a while) denotes a different slot.  This name-to-
slot mapping is important because it's the mapping which is inherited by
nested functions.

This is most clearly shown by example.  Consider this Python
interaction.

In [1]: l = []

In [2]: for i in [1, 2, 3]:
   ...:   l.append(lambda: i)
   ...:

In [3]: [f() for f in l]
Out[3]: [3, 3, 3]

This prints [3, 3, 3].  What's happened is that the lambdas have closed
over the prevailing /binding/ of i -- i.e., which reference slot it
denotes.  Since the for loop operates by assignment, and /not/ by
rebinding i, the three lambdas all closed over the same environment, and
return the same value.

Scheme's DO loop, by contrast, really does operate by binding.  Consider
this example of a GNU Guile interaction.

guile (define l '())
guile (do ((i (list 1 2 3) (cdr i)))
...((null? i))
...  (set! l (append l (list (lambda () (car i))
guile (map (lambda (f) (f)) l)
$1 = (1 2 3)

That is, each time through the loop, the variable I denotes a
/different/ reference slot; the LAMBDAs close over different
environments, and the functions return different values.  (This example
illustrates both binding and assignment, since the SET! changes the
value referred to in the slot denoted by L, without rebinding L.)

A very approximate translation of the above into Python looks like this.

In [1]: l = []

In [2]: items = [1, 2, 3]

In [3]: def _loop(ix):
   ...:   if ix = len(items): return
   ...:   l.append(lambda: items[ix])
   ...:   _loop(ix + 1)
   ...:

In [4]: _loop(0)

In [5]: [f() for f in l]
Out[5]: [1, 2, 3]

(I've cheated and used indices because Python lists don't have the
head/tail structure of Lisp lists.)

None of this is a criticism of Python's behaviour.  (Sometimes it'd be
nice if `for' worked by rebinding, but sometimes it's better that it
doesn't.)  But it is a criticism of the Python community's confusing use
of the word `binding' to mean something different from 

Re: why cannot assign to function call

2009-01-06 Thread Mark Wooding
Steven D'Aprano ste...@remove.this.cybersource.com.au wrote:

 I don't think so. Variables in algebra are quite different from variables 
 in programming languages. Contrast the statement:
 
 x = x+1
 
 as a programming expression and an algebraic equation. As a programming 
 expression, it means increment x by one. But as an algebraic 
 expression, it means x is some value such that it is equal to one more 
 than itself, and there is no solution to such an equation.

Surely there is.  The solution is: 1 = 0 (and hence x is an -- no, /the/
-- element of the trivial ring).

  and how several generations of computer languages, not to mention
  the actual machine language those generated, behaved, before the current
  crop.
 
 Sure. And?

Actally, this is true only for /very/ small values of `several'.  There
was FORTRAN in 1957, with what you're calling the `named bins' model,
and I call assignment-is-copying, and Lisp in 1958, with the assignment-
is-pointer-diddling model.

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-06 Thread Mark Wooding
Derek Martin c...@pizzashack.org wrote:

 I think I have though, not that it matters, since that was never
 really my point.  Python's assignment model requires more explanation
 than the traditional one, simply to state what it does.  That alone is
 evidence (but not proof).

Hmm.  Actually, it's not the assignment model which is strange at all.
It's the data model.  What does an expression like

  [1, 2, 3]

denote?  Is it the list itself, or a /reference/ to the list?  If you
answer the first, you'll want Tcl/C/Fortran semantics.  If you answer
the second, you'll want Lisp/Python/Javascript semantics.  If you answer
`it depends', you'll want to be confused.

Python decided that all values are passed around as and manipulated
through references.  (There are no locatives: references are not values,
and you can't have a reference to a reference.)  Lists store references;
tuples store references; and so on.

If one is to be able to implement complex data structures which involve
sharing of data (e.g., cyclic graphs) or which allow efficient
reorganization (e.g., various kinds of trees) we need to be able to
manage references to values somehow.  There are a number of ways of
doing this.

  * Everything is a reference.  This is the most uniform.  Once you've
got the hang of it, there are no surprises.

  * Nothing is a reference.  If you want complex data structures, you're
either screwed (e.g., if your data model is too weak) or you have to
invent them yourself using array indices or something wretched like
that.  Tcl is in this category: you have to mess with (associative)
arrays or variable names to make complex data structures.

  * Some values are references to others.  This is like C, and causes
exciting problems when you get confused.  C++ makes things more
confusing because dereferencing can happen implicitly.  Perl manages
to be in this camp /and/ the first one.  It's very strange.

  * Some things are references, and some aren't.  This is what Java and
C# do.  Java says that only simple, atomic things are
non-references, so assignment looks the same either way, but you
can't store primitive things in containers expecting to store
references (until Sun added automatic boxing and unboxing --
eventually).  C# makes matters more complicated by letting users
define structured mutable data which aren't handled by reference,
but does the boxing and unboxing thing transparently.

 As for there being no assignment in algebra, is that not really what
 variable substitution is? 

No.

 They have different names, but in my estimation they perform exactly
 the same function.  You're assigning specific values to the variables
 in an expression so that you can solve for a constant... just like in
 a computer program.

When you do this, you construct a different expression.  They might have
equal values, but they're still different.  (You can consider
equivalence classes under some appropriate equivalence relation if you
like, but that just makes things more complex.)

 There is even an allocation of memory: it's in your brain. :D

Ahh!  You're modifying a memory location in your brain so that it refers
to a different expression.  Isn't this the Lisp/Python/Javascript model?
;-)

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-06 Thread Joe Strout

Mark Wooding wrote:


Derek Martin c...@pizzashack.org wrote:


I think I have though, not that it matters, since that was never
really my point.  Python's assignment model requires more explanation
than the traditional one, simply to state what it does.  That alone is
evidence (but not proof).


Hmm.  Actually, it's not the assignment model which is strange at all.
It's the data model.  What does an expression like

  [1, 2, 3]

denote?  Is it the list itself, or a /reference/ to the list?  If you
answer the first, you'll want Tcl/C/Fortran semantics.  If you answer
the second, you'll want Lisp/Python/Javascript semantics.  If you answer
`it depends', you'll want to be confused.


Well said!

You can easily see that assignment in Python is perfectly ordinary, by 
comparing it to languages that have both values and references (such as 
C++, Java, or REALbasic).  Those languages have only one assignment 
model, that operates on both values and references just fine.


Python has only references, and I think it's for this reason that some 
people here try to pretend that it doesn't have them at all, thus 
leading them to weird explanations of strange assignment and 
argument-passing behavior.



Python decided that all values are passed around as and manipulated
through references.  (There are no locatives: references are not values,
and you can't have a reference to a reference.)


Also very clearly put.

If you don't mind, I may crib some of your verbage for 
http://www.strout.net/info/coding/valref/, as it may be clearer than 
my own.


Best,
- Joe



--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-06 Thread sturlamolden
On Jan 2, 5:43 pm, Steve Holden st...@holdenweb.com wrote:
 Derek Martin wrote:
  On Tue, Dec 30, 2008 at 02:21:29PM +, John O'Hagan wrote:
 [...]
  What the Python community often overlooks, when this discussion again
  rears its ugly head (as it seems to every other hour or so), is that
  its assignment model is BIZARRE, as in it's conceptually different
  from virtually all other languages substantially taught in
  undergraduate computer science programs.  And for that matter, it's
  pretty unintuitive generally.

 I'd definitely argue against bizarre. It's actually very easy to
 understand, and Python is by no means the only language to have used it.

A statement like

f(x) = 1

has no meaning in most languages - including Python, C and Java.

C++ references allows operator= to be overloaded. It is one of few
languages where a statement like 'f(x) = 1;' maybe meaningful. But C++
references are addresses (pointers in disguise), not names. The = is
Python's name binding operator. Python is similar to Java in this
respect. If anything is bizarre here, it is C++ references.

P.S. The C statement '*f(x) = 1;' does have meaning, but 'f(x) = 1;'
do not. But in the former case, one is not assigning to the return
value. Python and Java do not have raw pointers like C.













--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-06 Thread sturlamolden
On Jan 2, 11:39 am, Derek Martin c...@pizzashack.org wrote:

 What the Python community often overlooks, when this discussion again
 rears its ugly head (as it seems to every other hour or so), is that
 its assignment model is BIZARRE, as in it's conceptually different
 from virtually all other languages substantially taught in
 undergraduate computer science programs.  And for that matter, it's
 pretty unintuitive generally.

For one thing, Python's 'assignment model' (an annoying buzzword) is
similar to that of Java. It cannot be that different from what is
thought in undergraduate CS classes.

But take a look at C++:

int foobar(int x) {
  // blahblah
}

Now a statement like 'foobar(x) = y;' can actually have a meaning.

Whereas,

int* foobar(int x) {
  // blahblah
}

would make the same statement illegal. I have yet to see undergraduate
students knowing the difference between C++ pointers and references
after attending an introductory CS course.

Try to do the same in, say, Java. You will see that is behaves like
Python.

And as for bizarreness, I feel that Python and Java is greatly
surpassed by C++. Note that C do not share the bizarreness of C++.




















--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-01-06 Thread Aaron Brady
On Jan 6, 8:03 am, Mark Wooding m...@distorted.org.uk wrote:
 Steven D'Aprano st...@remove-this-cybersource.com.au wrote:
snip
  It seems that you don't include in the Python community all those who
  use the term name binding instead of variable assignment
  specifically because it gives new users a clue that Python is not the
  same as C.

 Unfortunately, this practice causes other confusion, since `binding' is
 often used (in other language communities, notably Lisp and the
 functional languages) to describe the association between names and
 slots that hold references.

 Let me explain.  I'll try to be clear, though I know that Stephen
 already understands this stuff well.

 At run-time, each named variable denotes a storage area (I'll call it a
 slot[2]) which holds a reference to some object[1].

               +-+
    name  | ref - object  
               +-+

 If we `assign' a different object to the variable, what really happens
 is that the slot is modified to refer to the other object; but the name
 continues to denote the same slot.

 Usually `binding', or `rebinding', a name describes a different process,
 whereby the name (for a while) denotes a different slot.  This name-to-
 slot mapping is important because it's the mapping which is inherited by
 nested functions.

Say you start with:
+--+
a  | ref1 - (1, 2, 3)
+--+
Then you can do:
+--+
a  | ref2 - (4, 5, 6)
+--+
But not:
+--+
a  | ref1 - (4, 5, 6)
+--+
That is, you can 'repoint a' to another 'ref', but not repoint a
'ref'.

I think one of the ideas we have trouble communicating is that [1, 2,
3] and [4, 5, 6] can be the same object (using '[:]='), but [1, 2, 3]
and [1, 2, 3] don't have to be.
--
http://mail.python.org/mailman/listinfo/python-list


  1   2   >