why cannot assign to function call
Mark Wooding
mdw at distorted.org.uk
Tue Jan 13 18:06:58 EST 2009
Steven D'Aprano <steven at REMOVE.THIS.cybersource.com.au> wrote:
> I found it interesting.
Well, that's something, at any rate.
> I think this conversation is reaching it's natural end. Frustration
> levels are rising.
I think you may be right. That said...
> So I'm going to take a different tack in an attempt to reduce
> frustration levels: if I can't convince the other side they're wrong,
> can I at least get them to understand where I'm coming from a little
> better?
Maybe...
> As I see it, this conversation is floundering on two radically different
> ideas about what it means to say a language uses pass-by-foo.
You might be right, but I'm unconvinced.
> On the one hand, some people (me and possibly rurpy) consider "this is
> pass-by-foo" to be a statement about behaviour directly visible to the
> programmer. We have a set of behavioral traits in mind, and if a language
> exhibits those behaviours, then it is clearly and obviously pass-by-foo
> no matter how that behaviour is implemented. I'll call these the
> behaviorists.
Here's the problem. I think I'm in that camp too!
I'm going to move away from the formal semantics stuff and try a
different tack. Here's what I think is the defining property of
pass-by-value (distilled from the formal approach I described earlier,
but shorn of the symbolism):
The callee's parameters are /new variables/, initialized /as if by
assignment/ from the values of caller's argument expressions.
I'd just like to examine that for a bit. Firstly, let's expand it from
the soundbite: basically what it says is that you should be able to
replace
function mumble(a, b, c) { stuff in terms of a, b, and c }
...
mumble(1 + 2, xyz, whatever)
with
...
fresh_a = 1 + 2
fresh_b = xyz
fresh_c = whatever
stuff in terms of fresh_a, fresh_b, and fresh_c
with no observable difference (here, fresh_a and so on are a variable
names not appearing in the rest of the program). So:
* It captures C's behaviour (at least if you don't count arrays --
let's not open that one again), and Pascal's normal behaviour.
Assigning to the parameters doesn't affect the caller's argument
variables because the parameters are fresh variables.
* It /doesn't/ capture Fortran's behaviour, or Pascal's `var'
parameters, because obviously assignment to parameters in Fortran
/can/ affect the caller's argument variables
* It also doesn't capture exotic things like Algol's call by name, and
lazy evaluation, because there's an evaluation step in there.
My soundbite definition for pass-by-reference is this:
The callee's parameters are merely /new names/ for the caller's
argument variables -- as far as that makes sense.
There's a caveat there for argument expressions which don't correspond
directly to variables -- and I've glossed over the issue of lvalue
expressions which designate locations and all of that. The idea is that
you can replace
function mumble(a, b) { stuff in terms of a and b }
...
mumble(xyz, whatever)
by
...
stuff in terms of xyz and whatever
This does indeed capture Fortran, and Pascal's `var', while excluding C
and Pascal non-`var'. Good!
So... obviously I'm going to claim that Python is pass-by-value. Why?
Because its argument passing works the same way as its assignment.
But! (you claim) ...
> Python simply can't be pass-by-value, because it doesn't behave like
> pass-by-value in other languages (particularly C and Pascal).
Ah! (say I) but assignment in C and Pascal looks different from the way
it looks in C -- and in exactly the same way that argument passing looks
different. And there, I think, I'm going to rest my case.
I'm sorry I took so long to distill these thoughts. Thank you for
putting up with my theoretical meanderings on the way.
-- [mdw]
More information about the Python-list
mailing list