What other languages use the same data model as Python?

  • Thread starter Steven D'Aprano
  • Start date
H

harrismh777

Grant said:
No, it isn't. It's pass by value. The fact that you are passing a
value that is a pointer to another value is not relevent.

@ Edwards, &Schaathun

You are most definitely mistaken. See:

http://publib.boulder.ibm.com/infoc.../com.ibm.xlcpp8a.doc/language/ref/cplr233.htm


I understand that semantically some people insist that when C receives
parms as pointers that pass-by-reference is only being simulated.

But that is the silliness of this argument... because down in the guts
of the ALU we only have direct and indirect memory addressing. Period.

You either pass a function the memory directly (value) or you pass the
data indirectly (reference).

Everything above that is high-level semantics.


If I want to pass values to my C functions, I can. If I want to pass
references to my C functions, I can.

If I want to implement a C language that does not use pointers directly
(hides them) I can implement pass by reference completely (on the
surface). In fact, I can implement the C compiler so that pass by value
is not allowed! [ it wouldn't look much like C, but its do-able ]


Everyone forgets that their high-level language is not 'really' what's
working... gcc does not produce machine code... it produces assembler
instructions that are passed to a translator... you can interrupt the
process and have it produce the assembly instructions so you can see
them if you want to... the point being, after all is said and done, all
you can do with today's von Neumann processors is pass data directly
(value) or indirectly (reference).

Everything else is semantics.
 
H

harrismh777

Hans said:
That does not in any way impugn C..;.
: quite the contrary, given enough time, C is better suited for modeling
: on a von Neumann processor, period.

What has that got to do with abstraction?

Everything, really.

Folks seem to think that because they are doing abstraction at a
high-level (well, they never maybe programmed at a lower level) that
abstraction somehow 'requires' a high level language. (not true)

Back in the day, our abstractions were encapsulated not in source, but
in psuedo-code, flow-charts, diagrams, and sometimes pretty pictures. It
all ended up in assembly and machine code.

Today, high-level languages like Python (and others) allow programmers
to place some of their abstraction into their source code directly. This
does not make the high-level language any more 'suited' to abstraction
than any other lower-level language; because the abstraction is a mental
process not a language feature. It all ends up in assembly and machine
code.


kind regards,
m harris
 
J

John Nagle

"Maybe"?

Given the following statement of Python code:


what is the value of the variable x? Is it...?

(1) The string "spam".

(2) Some invisible, inaccessible, unknown data structure deep in the
implementation of the Python virtual machine, which the coder cannot
access in any way using pure Python code.

(Possibly a pointer, but since it's an implementation detail, other
implementations may make different choices.)

(3) Something else.


I argue that any answer except for (1) is (almost always) counter-
productive: it adds more confusion than shedding light. It requires
thinking at the wrong level, at the implementation level instead of the
level of Python code. If we define "value" to mean the invisible,
inaccessible reference, then that leaves no word to describe was the
string "spam" is.

(I say "almost always" counter-productive because abstractions leak, and
sometimes you do need to think about implementation.)

Yes. In Python, the main leak involves the "is" operator and the
"id()" function. Consider:
x = "spam"
y = "spam"
x == y True
x is y True
z = x + 'a'
z = z[:4]
z 'spam'
x is z False
x == z True
id(x) 30980704
id(y) 30980704
id(z)
35681952

There, the abstraction has broken down. x, y, and z all reference
the value "spam", but they reference two, not one or three, instances
of it.

Arguably, Python should not allow "is" or "id()" on
immutable objects. The programmer shouldn't be able to tell when
the system decides to optimize an immutable.

"is" is more of a problem than "id()"; "id()" is an explicit peek
into an implementation detail. The "is" operator is a normal
part of the language, and can result in weird semantics. Consider
False

That's a quirk of CPython's boxed number implementation. All
integers are boxed, but there's a set of canned objects for
small integers. CPython's range for this is -5 to +256,
incidentally. That's visible through the "is" operator.
Arguably, it should not be.

John Nagle
 
G

Grant Edwards

@ Edwards, &Schaathun

You are most definitely mistaken.

The "pass by value" and "pass by reference" parameter passing
mechanisms are pretty well defined, and C uses "pass by value".
I understand that semantically some people insist that when C
receives parms as pointers that pass-by-reference is only being
simulated.

And they are right.
If I want to pass values to my C functions, I can. If I want to pass
references to my C functions, I can.

We're not talking about what _you_ do. We're talking about what the C
_compiler_ does. The C compiler passes by value -- always.
If I want to implement a C language that does not use pointers directly
(hides them) I can implement pass by reference completely (on the
surface).

That wouldn't be C.
In fact, I can implement the C compiler so that pass by value is not
allowed! [ it wouldn't look much like C, but its do-able ]

If you don't pass by value, it's not a C compiler.
Everyone forgets that their high-level language is not 'really'
what's working... gcc does not produce machine code... it produces
assembler instructions that are passed to a translator... you can
interrupt the process and have it produce the assembly instructions
so you can see them if you want to... the point being, after all is
said and done, all you can do with today's von Neumann processors is
pass data directly (value) or indirectly (reference).

I have no idea what your point is.

At the machine level, there _is_ nothing but values. You can use a
value as an integer, or as a pointer. It's still just a value. But
we're talking about parameter passing mechanisms defined by high-level
language specifications -- particularly C.
 
I

Ian Kelly


That source actually supports the claim that pass-by-pointer falls
under pass-by-value. It reads, in part (emphasis added):
In C++, the reference parameters are initialized with the actual arguments when the function is called. In C, the pointer parameters > are initialized with pointer _values_ when the function is called.

However, I hope we can all agree that pass-by-pointer shares certain
features with both pass-by-value and pass-by-reference, and there are
perfectly reasonable arguments for lumping it in either category, yes?
 
H

harrismh777

John said:
Arguably, Python should not allow "is" or "id()" on
immutable objects. The programmer shouldn't be able to tell when
the system decides to optimize an immutable.

"is" is more of a problem than "id()"; "id()" is an explicit peek
into an implementation detail.

Yes, yes, yes... and I'll go you one more...

.... Python should optimize on *all* immutables when possible.


For instance:

a = (1,2,3)
b = (1,2,3)

a == b True

a is b False

To be consistent, in this case and others, a and b should reference
the same immutable tuple.


Or, as stated earlier, Python should not allow 'is' on immutable objects.


kind regards,
m harris
 
H

harrismh777

Ian said:
However, I hope we can all agree that pass-by-pointer shares certain
features with both pass-by-value and pass-by-reference, and there are
perfectly reasonable arguments for lumping it in either category, yes?

Yes.
 
H

harrismh777

Grant said:
The "pass by value" and "pass by reference" parameter passing
mechanisms are pretty well defined, and C uses "pass by value".

Yeah, that's kind-a funny, cause I'm one of the guys (old farts) that
helped define them....


The problem you're having here is that you're thinking of parameter
passing 'mechanisms' and not focusing on the definition of the terms.

A reference is a pointer (an address).

A value is memory (not an address).


These definitions go all the way back before the 8080, or the 6502, 8
bit processors. Pass by reference has 'always' meant pass by using a
memory address (indirect addressing); a reference has always been a
memory pointer.


If I call a function in C, and pass-by-value, the data's 'value' is
placed on the stack in a stack-frame, as a 'value' parm... its a copy of
the actual data in memory.

If I call a function in C, and pass-by-reference, the data's 'address'
is placed on the stack in a stack-frame, as a 'reference' parm... no
data is copied and the function must de-reference the pointer to get to
the data.... this is by definition.



There may be some language somewhere that does pass-by-reference which
is not implemented under the hood as pointers, but I can't think of
any... 'cause like I've been saying, way down under the hood, we only
have direct and indirect memory addressing in today's processors. EOS.

If you pass a parm, you can either pass a copy (value) or pass a
reference to its location (not a copy, a reference).


kind regards,
m harris
 
M

Mark Hammond

Yeah, that's kind-a funny, cause I'm one of the guys (old farts) that helped define them....

Cool - please tell us more about your involvement in that. Obviously
lots of people were in the industry then, but only a select few would be
able to claim they helped define those terms.
There may be some language somewhere that does pass-by-reference which
is not implemented under the hood as pointers, but I can't think of
any... 'cause like I've been saying, way down under the hood, we only
have direct and indirect memory addressing in today's processors. EOS.

What about Python, where passing an integer to a function passes a
pointer to an int object, but that function is able to change the value
of the variable locally without changing the passed object (indeed, it
is impossible to change the passed integer)?

So given the definitions above, Python uses a by-reference mechanism but
(in some cases) has by-value semantics.

While I understand exactly how things work (so don't need an
explanation), the point is that for anything close to a high-level
language, things aren't as black and white as they are for the low-level
languages...

Mark
 
C

Chris Angelico

* that the paper tag is tied to only one object

* that a paper tag tied to no object is rather useless

* that many paper tags can be tied to the same object

I disagree minorly; a tag tied to no object is quite useful in some
circumstances. You can ditch the concept by having a special object
that's called "No Object" (Python does this, with None), or you can
allow your tag to point nowhere (C does this, with null pointers). The
difference is semantic; either way, your tag can point to any object
or it can point nowhere. (Pike goes for a slightly different approach;
any variable, regardless of its stated types, may legally hold the
integer 0. It acts somewhat as a null pointer, but it isn't really.)

Chris Angelico
 
G

Gregory Ewing

Hans said:
Is transmission by name the same as call by object?

No, it's not. With call-by-name, the caller passes a
small function (known as a "thunk") that calculates the
address of the parameter. Every time the callee needs to
refer to the parameter, it evaluates this function.

This allows some neat tricks, but it's massive overkill
for most uses. In later languages, the functionality of
call-by-name has been replaced by the ability to explicitly
pass functions as parameters.
Anyway, I have never seen anyone counting more than
three ways of doing this ...

There are other possibilities, such as value-result,
where a local copy is made and its final value is
copied back before returning. I think Fortran is
defined in such a way that this is an acceptable way
of implementing parameter passing. It's also the
only way of getting anything akin to by-reference
over an RPC connection.

But for most situations, by-value and by-reference
cover anything you might want to do. And if you
have a dynamic data model like Python, you don't
even need by-reference.
 
H

harrismh777

Mark said:
What about Python, where passing an integer to a function passes a
pointer to an int object, but that function is able to change the value
of the variable locally without changing the passed object (indeed, it
is impossible to change the passed integer)?

So given the definitions above, Python uses a by-reference mechanism but
(in some cases) has by-value semantics.

Yeah, Mark, the trouble is that the concepts (by-value, or
by-reference) have morphed into a concept(s) that say something of what
should or should not happen within scopes (or, in the case of Python,
namespaces) and says something less about what 'reference' or 'value'
mean as terms for data. So, again, its semantics... not black and white,
as you say and some of both|and.

If C were 'strictly' pass-by-value (that is what the K&R states,
sec. 1.8, p27 2nd ed) and had no concept of indirect memory addressing
(memory references is what we called them in the early days ca. 1970~)
in the form of pointers, then all of this semantic discussion would be
mute. But, 'C' does provide for pointers which are used by all 'C'
programmers to firmly provide pass-by-reference in their coding (C++
also, by the way). My 'C' functions can most definitely modify the parms
passed in from their calling functions by simply 'de-referencing' the
parms. This is done all the time--- and a good thing too, since nobody
would want to pass a list by value, or worse yet a linked list with a
couple of thousand nodes, by value.

So, I argue that its silly to say that because the parameter passing
'mechanism' of the 'C' language is pass-by-value (see K&R) that 'C' is a
pass-by-value language, when clearly 'C' programmers use
pass-by-reference routinely in their 'C' coding. This is quite different
than some flavors of Fortran or Pascal where the called routines had
access to the original vars--- which had more to do with scope than it
did with parameter passing or indirection. In 'C' if I want to I can
live with pass-by-value... or, I can live with pass-by-reference
nicely... and its up to me... not language constraints. Again, it seems
that some folks want to pigeon hole this concept into one or the other
(and it clearly can be) but usually it is a combination of the two (both
| and).

kind regards,
m harris
 
J

John Nagle

Yes, yes, yes... and I'll go you one more...

... Python should optimize on *all* immutables when possible.


For instance:

a = (1,2,3)
b = (1,2,3)

a == b True

a is b False

To be consistent, in this case and others, a and b should reference
the same immutable tuple.

Actually, that's not necessarily an "optimization". The cost of
looking up small tuples is probably higher than creating them.
There's also a potential optimization of duplicating tuples in
use by different threads, to reduce locking effort. (CPython's
global lock is too dumb to exploit this, but there are other ways
to do it.)
Or, as stated earlier, Python should not allow 'is' on immutable objects.

A reasonable compromise would be that "is" is treated as "==" on
immutable objects.

John Nagle
 
H

harrismh777

Tim said:
The fact that the parameter "a"
in BumpMe happens to be an address is completely irrelevent to the
definition of the parameter passing mechanism.

C has pass-by-value, exclusively. End of story.

Yeah, Tim, I know... but that's my entire point in a nut-shell...
whether the language is pass-by-value or pass-by-reference has less to
do with how it is 'defined' (its mechanism--- indirection and stack) and
more to do with how it is routinely used with the standard features it
provides--- in this case memory indirection--- as pointers.

Something new here, just for fun...

.... I ran my hello.c program through the gcc compiler and intercepted
its assembly source output. Some folks on the list may not know that the
gcc compiler used to generate CPython (at least on *nix systems) does
not generate object or machine code directly, but generates an
intermediate assembly source in AT&T syntax. The assembly code is
interesting for the discussion, if you've never seen it. If you have,
blow this off.

Anyway, I built a small wrapper called 'say()' around the printf
function, so that I could pass a string var to say(), and I then called
it a couple of times in main(). The assembly source code is listed at
the end of this post. The thing to notice here is two things:
1) assembly code is actually being used to generate the machine
code, not 'C' (and this is true for Python as well, compiled from
sources) In other words, Python interpreter does not do anything more
(nor less) than what can be done with assembler (nor machine code for
that matter). And,
2) The strings I am 'passing' to the say() function don't get
'passed' anywhere. (I know that most of you know this, bear with me) The
strings are set in memory, and through memory indirection pointers (the
parenthesis 'references') the string's memory addresses are placed on
the stack. The called routine say() has full access to the original
strings in memory (via their memory addresses) if necessary. The main
point being that the say() function has a 'reference' to the original,
and not a local copy of the 'value', and it can change it! The string's
addresses are .LC0 and .LC1/

Here is the assembly of my hello.c saved as hello.s with:

gcc -Wall -S -o hello.s hello.c


.file "hello.c"
.section .rodata
..LC0:
.string "\nhello, world!\n"
.align 4
..LC1:
.string "...and again I say, hello there, world!\n\n"
.text
..globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
movl $0, 28(%esp)
movl $.LC0, (%esp)
call say
movl $.LC1, (%esp)
call say
movl 28(%esp), %eax
leave
ret
.size main, .-main
.section .rodata
..LC2:
.string "%s"
.text
..globl say
.type say, @function
say:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl $.LC2, %eax
movl 8(%ebp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
leave
ret
.size say, .-say
.ident "GCC: (Ubuntu 4.4.1-4ubuntu9) 4.4.1"
.section .note.GNU-stack,"",@progbits
 
H

Hans Georg Schaathun

No, it's not. With call-by-name, the caller passes a
: small function (known as a "thunk") that calculates the
: address of the parameter. Every time the callee needs to
: refer to the parameter, it evaluates this function.

Well, call-by-name is not the same as transmission by name either.
Transmission by name is what most posters here call call by
reference, and transmission by reference is what this thread calls
object sharing or call by object.

No wonder I started off confused :) It is better now.
 
D

Dennis Lee Bieber

We do not consider passing a pointer as *by value* because its an
address; by definition, that is pass-by-reference. We are not passing

To most of the world, pass-by-reference means the COMPILER, not the
PROGRAMMER is obtaining and passing the address, and the compiler also
always dereferences the passed "value"... The programmer has no control
over whether to operate on the address or the data referenced by the
address.
 
H

Hans Georg Schaathun

Folks seem to think that because they are doing abstraction at a
: high-level (well, they never maybe programmed at a lower level) that
: abstraction somehow 'requires' a high level language. (not true)

I never said 'requires', but when you do high-level modelling,
low-level detail is a distraction. Using a low-level language
for abstract modelling is therefore harder than it needs to be.

: Today, high-level languages like Python (and others) allow programmers
: to place some of their abstraction into their source code directly. This
: does not make the high-level language any more 'suited' to abstraction
: than any other lower-level language; because the abstraction is a mental
: process not a language feature. It all ends up in assembly and machine
: code.

Indeed, except for the contradiction. The fact that you can
put more of your abstraction into the source code means that it is
better suited to abstraction.

Mental processes depend on language; at least when you need to
communicate the output. That language does not have to be
computer readable (as is the case for your float charts etc).
We may very well use a stack of languages and models at different
levels of abstraction, but when you move down the stack you are
moving away from abstraction and into implementation.

C is very rarely suitable at the top of this stack. When I say that
C is ill-suited for abstraction, I am not implying that it is ill-suited
for implementing according to an abstract model. If you need human
input in the lower layers of abstraction, C is a good choice.

Using manual work to move down the layers of abstraction is possible,
and given sufficient man-power should give the better result, but
relying on human input when the work can be automated is ridiculously
expensive.

Now, python is only one level above C in abstraction, but that's a
different matter.
 
H

Hans Georg Schaathun

A reference is a pointer (an address).
:
: A value is memory (not an address).

Sure, and pointers (from a hardware or C perspective) are memory,
hence pointers are values.
 
G

Gregory Ewing

Hans said:
With the references being
purely abstract entities and not data objects,

It's not clear to me that references are any more abstract
than objects, or to put it another way, that objects are
any less abstract than references.

After all, in normal Python usage you never actually
*see* an object -- at best you see some string of characters
resulting from the str() or repr() of an object. The
object is a mental construct we use to make sense of the
behaviour we're seeing, as are references.

If you were to look inside the interpreter closely enough
to see the concrete representations of objects -- the
bit patterns in memory making them up -- then you would
also be able to see the bit patterns making up the
references.
 

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,598
Members
45,145
Latest member
web3PRAgeency
Top