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

Reply via email to