A question on modification of a list via a function invocation

Steve D'Aprano steve+python at pearwood.info
Mon Sep 4 22:49:23 EDT 2017


Dennis,

That's an excellent summary of a number of programming languages' calling
conventions, thank you.

Unfortunately you have the X-No-Archive header set, so it will be lost to
prosperity. To prevent that, I'm taking the liberty of quoting you in full
below (and top posting).

A couple of comments:

> I don't have Java textbooks locally (in storage 15 miles away) but from
> what I recall, it too has the complication of splitting between "simple
> types" and "reference types" ("boxed" I believe is the term used in books).

You remember correctly.

Java supports machine primitive values like ints and floats, and always treats
them as by-value. You can also "box" them in an object, in which case Java has
precisely the same semantics as Python, Ruby and many others, pass by object
sharing. But the Java community insists on calling it pass by value.
Occasionally, when they remember or when pressed, they will admit that what is
being passed by value is not the object (the value), but an invisible,
unknowable, implementation-dependent reference to the actual value.


> The default passing mechanism would be similar to the description of C#
> ("boxed" types being implicit copies of references allowing mutation
> in-place, but assignment to the parameter itself has no effect on the
> caller).

Indeed.

> I suspect it too has some means to explicitly produce a 
> by-reference parameter.

I've never come across a by-reference mechanism is Java. Scott Stanchfield gives
the litmus test for pass-by-reference semantics: can you write a "swap"
procedure in the language? He gives examples of a swap() procedure in
pseudocode, Pascal and C++, and specifically says "you cannot do this in Java".

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

But of course you can simulate (poorly) by-reference output parameters in Java,
or Python, using mutation, just as you can simulate (poorly) by-reference
output parameters in C with pointers and mutation of the memory location
pointed to.

Scott describes himself as "a compiler guy at heart", and that leads him to
confuse abstraction levels. He is absolutely correct that the Java compiler
always passes by value. But that's not the Java language, that is the
implementation of the Java language. Here is Scott's category error:

    [quote]
    The mistake they make is in the definition of

    Figure 7: (Java) Defining a Dog pointer
    Dog d;

    itself. When you write that definition, you are defining a pointer to a Dog
    object, not a Dog object itself.
    [end quote]


Here Scott mixes up what the compiler does (creates a pointer to a Dog object,
and what the programmer's Java code does (creates a Dog).

I expect this is because, as a "compiler guy", Scott probably doesn't really
believe that objects are values. Values are small machine primitives, like a
64-bit float, not big, complicated, compound structures of methods and
attributes like objects.

On category errors: https://en.wikipedia.org/wiki/Category_mistake



On Tue, 5 Sep 2017 05:12 am, Dennis Lee Bieber wrote:

> On 4 Sep 2017 16:51:45 GMT, ram at zedat.fu-berlin.de (Stefan Ram) declaimed
> the following:
> 
>>
>>  I am assuming that there are two argument passing mechanismss
>>  in the languages mentioned by me (C, C++, VBA, C#, Java,
>>  JavaScript, and Python):
> 
> Original (and maybe still) C only has one native passing convention:
> pass by value. Arguments go in, but they do not come out.
> 
> C relied upon the /programmer/ to explicitly obtain the address of a
> memory location (by using & upon the argument) with the obtained address
> now being passed by value. C also relied upon the programmer to explicitly
> dereference the parameter in order to access the desired value.
> 
> int afunc(int x, int * y)
> {
> int z;
> z = x + y;    /* whoops, forgot to dereference y */
> return (- *y);        /* this time remembered */
> }
> 
> ...
> int a;
> int b;
> 
> z = afunc(a, b);      /* whoops, forgot to obtain address of b */
> z2 = afunc(a, &b);    /* correct usage */
> 
> C++ has added a reference declaration in the definition of functions,
> thereby making the obtaining/dereferencing automatic.
> 
> int bfunc(int x, int & y)
> {
> int z;
> z = x + y;    /* automatic derefence */
> return -y;
> }
> 
> z = bfunc(a, b);      /* automatic address */
> 
> 
> Classic FORTRAN is always pass-by-reference(location) -- though DEC VMS
> FORTRAN had compile-time "functions" which could override that: %ref,
> %descr, %val (and I think there was a %loc which would return the address
> of the argument -- it wasn't used for parameter passing itself).
> 
> Pascal, probably Modula-2, Visual BASIC are closer to the C++ reference
> semantics, in that the definition of a function declares how the
> argument(s) are passed.
> 
> Pascal and Modula-2 default is by-value, unless the parameter is
> declared with "var "
> 
> VB-6 defaulted to by-reference and relied upon the use of "ByVal " in
> the declaration to cause a by-value pass. VB.NET (part of the managed
> common language runtime [CLR]) and later default to by-value and require
> "ByRef " in the declaration to get reference semantics ("ByVal " is still
> valid).
> 
> Unless there have been changes I've not been exposed to, VBA was a
> subset of VB-6 (I don't know if it is now a subset of VB.NET and CLR)
> 
> Ada has declarations of "IN", "OUT", and "IN OUT"... But these really
> define how the parameter may be used within the function, and do not
> enforce any particular passing semantics (commonly, numeric types are
> pass-by-value for IN declarations, but arrays, strings, etc. will be
> pass-by-reference; the compiler generates code to prevent writing to IN
> parameters. I believe later Ada standards might mandate that "IN OUT" is
> treated as by-reference; Ada 80 may have permitted value-result semantics)
> 
> C# (another CLR language) complicates matters by first having "simple
> types" (essentially the basic numeric types) and "reference types"
> (strings, arrays, everything else). The default passing mechanism is
> call-by-value -- which for "reference types" is a copy of the address of
> the object (so you can do in-place mutation of those objects, but you can
> not replace the object itself with a new object). But then it supports
> "ref" and "out" modifiers for the declaration ("out" allows for the use of
> uninitialized names in the caller, with the function providing the first
> initialized content). Passing a "reference type" using "ref" means passing
> a reference to a reference, and the function can then replace the original
> object.
> 
> I don't have Java textbooks locally (in storage 15 miles away) but from
> what I recall, it too has the complication of splitting between "simple
> types" and "reference types" ("boxed" I believe is the term used in books).
> The default passing mechanism would be similar to the description of C#
> ("boxed" types being implicit copies of references allowing mutation
> in-place, but assignment to the parameter itself has no effect on the
> caller). I suspect it too has some means to explicitly produce a
> by-reference parameter.
> 
> Python... does not have this dichotomy of "simple" and "reference"
> types -- everything is a "reference" type but may be immutable or mutable;
> mutable can be modified in-place, immutables can not be modified.
> Assignment to a parameter name replaces the object locally, with no effect
> on the argument provided by the caller. There is no provision to expose a
> reference (to a reference) nor to dereference any thing.

-- 
Steve
“Cheer up,” they said, “things could be worse.” So I cheered up, and sure
enough, things got worse.




More information about the Python-list mailing list