What other languages use the same data model as Python?

  • Thread starter Steven D'Aprano
  • Start date
C

Chris Angelico

Well, its certainly Monte-esq.... I like it, whoever said it.

Same style of humour, they both derived significantly from Spike
Milligan and "The Goon Show". That particular quote relates to the
famous computer that calculated the number 42, which - to drag this,
kicking and screaming, back to some semblance of on-topicness - was
clearly built with a view to conserving programmer time at the expense
of execution time. I don't understand why they didn't just recode the
heavy computation in C and cut it down to just a few thousand years...

Chris Angelico
 
G

Gregory Ewing

Hans said:
You cannot reference nor manipulate a
reference in python, and that IMHO makes them more abstract.

You can manipulate them just fine by moving them
from one place to another:

a = b

You can use them to get at stuff they refer to:

a = b.c
a[:] = b[:]

You can compare them:

if a is b:
...

That's about all you can do with pointers in Pascal,
and I've never heard anyone argue that Pascal pointers
are any more or less abstract than any other piece of
data in that language.

As for "referencing" a reference, you can't really do
that in Pascal either, at least not the way you can
in C, because (plain) Pascal doesn't have an address-of
operator. The only way to get a pointer to a pointer
in Pascal is to heap-allocate a single pointer, which
isn't normally a very useful thing to do.
 
C

Chris Angelico

You can manipulate them just fine by moving them
from one place to another:

I think "manipulate" here means things like pointer arithmetic, which
are perfectly normal and common in C and assembly, but not in
languages where they're references.

Chris Angelico
 
G

Gregory Ewing

John said:
Such tuples are still identical, even if they
contain identical references to immutable objects.

The point is you'd have to do the comparison only one
level deep, so it wouldn't be exactly the same as ==
on tuples.
 
G

Gregory Ewing

But to use 'name' as a complete replacement for 'variable',
you have to stretch it to include things like a, b.c,
e.f(x).g[i:j].k, etc. which goes rather a long way beyond
the everyday meaning of the word.

In Python I use 'variable' to mean more or less 'something
that can be assigned to', which accords with the way it's
used in relation to many other languages, and doesn't
suggest any restriction to things named by a single
identifier.

Seems to me that anyone taking that connotation from it
has not yet been sufficiently educated about the Python
data model itself. Part of explaining that data model
consists of instilling the very idea that the things in
Python that are analogous to variables in other languages
only refer to data rather than containing the actual data.

But I don't say "has a value", I say "refers to".
 
G

Gregory Ewing

Andreas said:
If True and False:
waveFunction.collapse(cat)

Call-by-entanglement would be interesting. Anything that the
callee does to the parameter would affect the caller, but
you would only be able to tell by examining a trace of the
output afterwards.
 
G

Gregory Ewing

Grant said:
if you feel it just right and you have just the


No, that's _not_ automatic if you have to do it yourself. It's
automatic when it happens without user-intervention.

Does it count if the transmission is activated
by saying "Home, Jeeves"?
 
T

TheSaint

Gregory said:
because modern architectures are so freaking complicated
that it takes a computer to figure out the best instruction
sequence

certainly is, I would not imagine one who writes on scraps of paper
:D :D :D
 
R

Roy Smith

Ben Finney said:
No, I think not. The term “variable†usually comes with a strong
expectation that every variable has exactly one name.

Heh. You've never used common blocks in Fortran? Or, for that matter,
references in C++? I would call either of those "two names for the same
variable".
 
G

Gregory Ewing

Chris said:
I think "manipulate" here means things like pointer arithmetic,

I don't believe that allowing arithmetic on pointers
is a prerequisite to considering them first-class values.
You can't do arithmetic on pointers in Pascal, for
example, but nobody argues that Pascal pointers are
not values.
 
G

Gregory Ewing

Ben said:
No, I think not. The term “variable†usually comes with a strong
expectation that every variable has exactly one name.

I would say that many variables don't have names *at all*,
unless you consider an expression such as a to be
a "name". And if you *do* consider that to be a name,
then clearly one variable can have a great many names.

What would *you* call a?
 
C

Chris Angelico

Ben said:
No, I think not. The term “variable” usually comes with a strong
expectation that every variable has exactly one name.

I would say that many variables don't have names *at all*,
unless you consider an expression such as a to be
a "name". And if you *do* consider that to be a name,
then clearly one variable can have a great many names.

What would *you* call a?


a is a variable; i is a variable; a is an expression. It's not a
single name, and if you had two variables i and j with the same value,
nobody would disagree that a and a[j] ought to be the same thing.
That's the whole point of arrays/lists/etc/etc. But if you want to fry
your noggin, wrap your head around REXX's compound variables:

a=5
b=3
array.a.b="Hello" /* see, this is a two-dimensional array */

c=63/10
array.c="world!" /* see, we can have non-integers as array indices */

d=a+1
result = array.a.b", "array.d.b /* "Hello, world!" */

So what is a "name" in REXX? You have to evaluate the compound
variable as a set of tokens, then evaluate the whole thing again, and
is that the name? Because the resulting "name" might not be a valid
identifier...

Yep, it's good stuff.

Chris Angelico
 
S

Steven D'Aprano

You can manipulate them just fine by moving them from one place to
another:

a = b

I see no reference there, nor do I see any moving taking place. What I
see is a name binding operation. What is happening is that the name "a"
is being bound to the object "b" (or to be precise, to whatever object is
currently bound to name "b").

Since you haven't explained what you think is happening, I can only
guess. My guess is that you are thinking about some implementation of the
Python VM which uses some sort of reference internally. Perhaps it's
CPython, which uses pointers, or some C++ implementation which actually
uses an indirect pointer-like data structure called "reference", or maybe
even some old-time FORTRAN I implementation that simulates pointers with
integer indexes into a fixed size array. It could be anything.

But whatever you're thinking of, it's not the behaviour of *Python* code,
it's behaviour of the Python virtual machine's implementation.

It astonishes me how hard it is to distinguish between abstraction levels
when discussing computer languages. We don't have this problem in other
fields. Nobody talking about (say) Solitaire on a computer would say:

"Blat the pixels in the rect A,B,C,D to the rect E,F,G,H. That will free
up the Ace of Spades and allow you to memcopy the records in the far
right column of the tableau into the foundation."

but when it comes to high-level computer languages like Python, we do the
equivalent *all the time*. (I include myself in this.) And people get
into (often angry) arguments over definitions, when what they're really
arguing about is what is happening at different abstraction levels.

A simplified view:


At the Python level: binding of objects to names. No data is copied
except by use of a direct "copy" instruction, e.g. slicing.

At the Python VM level: objects pushed and popped from a stack.

At the VM implementation level: Name binding may be implemented by
copying pointers, or some other reference, in some data structure
representing name spaces. Or by any other mechanism you like, so long as
the behaviour at the Python level is the same.

At the assembly language level: memory is copied from one address to
another.

At the hardware level: we usually describe bit manipulation in terms of
binary AND, XOR and OR, but even that may be an abstraction: it's
possible that the only binary op physically used by the machine is NAND.
 
H

harrismh777

Steven said:
Nobody talking about (say) Solitaire on a computer would say:

"Blat the pixels in the rect A,B,C,D to the rect E,F,G,H. That will free
up the Ace of Spades and allow you to memcopy the records in the far
right column of the tableau into the foundation."

but when it comes to high-level computer languages like Python, we do the
equivalent *all the time*.

I find exception to that argument. That is an example of the bogus
analogy fallacy. (I am offering this in friendship, actually). The two
cases have nothing to do with one another, do not affect one another
directly or indirectly, and are not helpful for comparison sake.
Analogies are generally not helpful in discussion and ought to be
avoided generally... except for entertainment sake... and frankly I have
found many of your analogies most entertaining (and creative) !

Second point, we seldom do anything *all the time* / this is a
fallacy that presupposes extreme references, as we think about the
argument; extreme exageration is not helpful... may or may not be
rightly extreme, and may or may not be relevant.

What can be said (about the argument) is that we sometimes waste
time arguing over abstraction layers with limited cross-dependent
understanding.

(I include myself in this.)

(myself, as well) ... the humility is appreciated.
And people get
into (often angry) arguments over definitions, when what they're really
arguing about is what is happening at different abstraction levels.

Sometimes. More often than not, folks are not really angry (I am
seldom angry at my computer terminal... its one of the places where I
relax, learn, communicate, and relate with other computer scientists who
enjoy what they do because its enjoyable. I do agree with you that we
all sometimes talk past each other because we're arguing from within a
'different' level of abstraction.



kind regards,
m harris
 
R

rusi

I see no reference there, nor do I see any moving taking place. What I
see is a name binding operation. What is happening is that the name "a"
is being bound to the object "b" (or to be precise, to whatever object is
currently bound to name "b").

Since you haven't explained what you think is happening, I can only
guess. My guess is that you are thinking about some implementation of the
Python VM which uses some sort of reference internally. Perhaps it's
CPython, which uses pointers, or some C++ implementation which actually
uses an indirect pointer-like data structure called "reference", or maybe
even some old-time FORTRAN I implementation that simulates pointers with
integer indexes into a fixed size array. It could be anything.

But whatever you're thinking of, it's not the behaviour of *Python* code,
it's behaviour of the Python virtual machine's implementation.

It astonishes me how hard it is to distinguish between abstraction levels
when discussing computer languages. We don't have this problem in other
fields. Nobody talking about (say) Solitaire on a computer would say:

"Blat the pixels in the rect A,B,C,D to the rect E,F,G,H. That will free
up the Ace of Spades and allow you to memcopy the records in the far
right column of the tableau into the foundation."

but when it comes to high-level computer languages like Python, we do the
equivalent *all the time*.

It has to be so -- because the Turing machine like the modern computer
is an unbelievable abstraction squasher. Yes unbelievable in the
sense that people simply cant come to terms with this. [Witness your
"It astonishes me..." Harris: "I take exception.." etc]

The modern computer (von Neumann) <- self-modifying code <- Data=Code
<- Undecidability (Halting problem) <- Consistency XOR Completeness
(Godels theorem(s)) <- Leaky Abstractions as inevitable

If anyone thinks Godels theorems are easy trivial, he probably does
not know what he is talking about, Yet we think that computers are
easy to understand?

[Ive personally witnessed PhDs in computer science not appreciate
compilers' inability to do certain things, and yet they could go and
take a bunch of lectures on the halting problem. What they understand
is anybody's guess :) ]

Coming back to topic: The argument (about bindings, variables etc)
arises because python (like lisp) is an imperative language
masquerading as a functional one.
Such arguments dont arise in Haskell or in assembly language.
They arise and are tolerable in C.
They are terrible in C++ because all the abstractions are built to
leak.

Where python sits in this (circular) spectrum is an interesting
question
(and I watch the arguments with much interest)
 
D

Dennis Lee Bieber

What would *you* call a?

Depending upon the nature of the beast, I'd be tempted to call it a
"fully qualified name" or a "partially qualified name"

a = [1, 2, 4, ("c", "d", "e")]

a is fully qualified if the object of interest is the entire
list [1, 2, 4, ["c", "d", "e"]]
it is partially qualified when the object of interest is an
element of the list

a is fully qualified if "i" represents an index of 0..3
and one is interested in any single element of the list, including the
sublist as a whole
it is partially qualified if "i" represents the index 3 AND one
is interested in an element of the sublist.

a[1] = 10

binds the fully qualified name "a[1]" to the object representing "10".
This just happens to also mutate the object denoted by the partially
qualified name "a".
 
C

Chris Angelico

What would *you* call a?

       Depending upon the nature of the beast, I'd be tempted to call it a
"fully qualified name" or a "partially qualified name"

       a = [1, 2, 4, ("c", "d", "e")]


Why is an integer more or less important than a tuple? a[3] is no less
qualified than a[2]; each of them points to an object. One of those
objects happens to contain other objects.

What if you had:
stdio = [stdin, stdout, stderr]

They might be 'file' objects, or they might be integers (unlikely in
Python), or they could be pipes or other file-like objects, or they
might be some kind of special tee object that contains two file
objects. Let's say your standard I/O uses the notation
stdout.write('message') and that you have a subclass of tuple that
will apply the . operator to all its members (is that possible in
Python? If not, pretend it is). You could then execute
stdio[1]=(stdout,teeobject) to easily copy your screen output to
another file. At this point, you can actually pretend that stdio[0]
and stdio[1] are identical objects, but you can use stdio[1][1] and
you can't use stdio[0][1] - which means that, per your definition, one
of them is only partially qualified.

As Inigo Montoya said, there is too much - let me sum up. Lists/tuples
and integers are equally objects, so whether or not you have a 'name'
is not affected by what type of object it points to.

Chris Angelico
 
G

Gregory Ewing

Steven said:
Since you haven't explained what you think is happening, I can only
guess.

Let me save you from guessing. I'm thinking of a piece of paper with
a little box on it and the name 'a' written beside it. There is an
arrow from that box to a bigger box.

+-------------+
+---+ | |
a | --+---------------->| |
+---+ | |
+-------------+

There is another little box labelled 'b'. After executing
'a = b', both little boxes have arrows pointing to the same
big box.

+-------------+
+---+ | |
a | --+---------------->| |
+---+ | |
+-------------+
^
+---+ |
b | --+-----------------------|
+---+

In this model, a "reference" is an arrow. Manipulating references
consists of rubbing out the arrows and redrawing them differently.
Also in this model, a "variable" is a little box. It's *not* the
same thing as a name; a name is a label for a variable, not the
variable itself.

It seems that you would prefer to eliminate the little boxes and
arrows and write the names directly beside the objects:

+-------------+
a | |
| |
b | |
+-------------+

+-------------+
c | |
| |
| |
+-------------+

But what would you do about lists? With little boxes and arrows, you
can draw a diagram like this:

+---+ +---+
a | --+----->| | +-------------+
+---+ +---+ | |
| --+----->| |
+---+ | |
| | +-------------+
+---+

(Here, the list is represented as a collection of variables.
That's why variables and names are not the same thing -- the
elements of the list don't have textual names.)

But without any little boxes or arrows, you can't represent the
list itself as a coherent object. You would have to go around
and label various objects with 'a[0]', 'a[1]', etc.

+-------------+
a[0] | |
| |
| |
+-------------+

+-------------+
a[1] | |
| |
| |
+-------------+

This is not very satisfactory. If the binding of 'a' changes,
you have to hunt for all your a labels, rub them out and
rewrite them next to different objects. It's hardly conducive
to imparting a clear understanding of what is going on,
whereas the boxes-and-arrows model makes it instantly obvious.

There is a half-way position, where we use boxes to represent
list items, but for bare names we just draw the arrow coming
directly out of the name:

+---+
a --------->| | +-------------+
+---+ | |
| --+----->| |
+---+ | |
| | +-------------+
+---+

But this is really just a minor variation. It can be a useful
shorthand, but it has the drawback of making it seem as though
the binding of a bare name is somehow different from the
binding of a list element, when it isn't really.

Finally, there's another benefit of considering a reference to
be a distinct entity in the data model. If you think of the
little boxes as being of a fixed size, just big enough to
hold a reference, then it's obvious that you can only bind it
to *one* object at a time. Otherwise it might appear that you
could draw more than one arrow coming out of a name, or write
the same name next to more than one object.

It seems to me that the boxes-and-arrows model, or something
isomorphic to it, is the most abstract model you can make of
Python that captures everything necessary to reason about it
both easily and correctly.
 
H

Hans Georg Schaathun

You can manipulate them just fine by moving them
: from one place to another:
:
: a = b
:
: You can use them to get at stuff they refer to:
:
: a = b.c
: a[:] = b[:]

Surely you can refer to the objects, but you cannot refer to
the reference.

: You can compare them:
:
: if a is b:
: ...

This could be implemented as pointer comparison, but it is not
defined as such and there is no requirement that it be.

: That's about all you can do with pointers in Pascal,
: and I've never heard anyone argue that Pascal pointers
: are any more or less abstract than any other piece of
: data in that language.

In Pascal a pointer is a distinct data type, and you can have variables
of a given type or of type pointer to that given type. That makes the
pointer a concrete concept defined by the languagedefined by the
language.
 

Ask a Question

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

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

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,165
Latest member
JavierBrak
Top