why cannot assign to function call

Joe Strout joe at strout.net
Fri Jan 9 16:30:46 CET 2009

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;

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 

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

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.

- Joe

More information about the Python-list mailing list