On Aug 26, 2019, at 08:38, Guido van Rossum <[email protected]> wrote:
>
> Sorry, there is no way to leverage the implementation or syntax of := for
> this purpose. You must be misunderstanding how they it works.
>
> You are right that the initial value of the variable at the call site is
> irrelevant (but there must be some initial value, e.g. None, to be able to
> identify the variable).
I’m not sure this is quite true.
I do think it would be an abuse of := syntax, and any design would be hard to
read and teach, but I don’t think it would be impossible to implement.
With traditional pass by reference, you need some kind of dereferencing
syntax—but once you have that, the “output” variables can be uninitialized.
Consider this C-style pattern (which you see all over the place in ObjC):
int func(Error* error = NULL) {
if (error) { *error = MyError; }
}
The actual out variable is *error, not error, and it’s optional, and it can be
passed uninitialized.
But I think the OP is looking for something more magical, where the function
definition just sees the Error rather than the Error*, and can just assign to
error (which, under the covers, assigns to *error with the null check). That
isn’t that hard to add to a C-style language—and it actually fits better into
Python, where there is no explicit dereferencing anywhere. And you can still
“pass” an uninitialized variable or leave it out, because you’re not really
passing anything, you’re just giving a name for the machinery to bind at the
end (which is just a normal assignment).
To make sure I understand the proposal, let me give a simplified but complete
use case so the OP can tell me it I got it wrong:
def fun(out := outvar):
outvar = 3
This isn’t valid syntax today; a := expression can appear in a default-value
expression or a type annotation, but it can’t appear directly as a parameter in
a parameter list. So, this would be entirely new syntax that could be made
legal.
And, once you do that, you can assign entirely new semantics.
This doesn’t assign a value to out, or even make it a local variable name; out
only exists for the calling machinery to get the name to bind.
It does make outvar a local variable name (adds it to the list of local names
in the code object), but that still doesn’t have to give it a value. It’s like
having “if False: outvar = None” at the top of the body.
What about on the call side? Here I’m not quite as sure, but I don’t think you
can have a := expression in an argument list without wrapping it in parens? If
so, then this is also new syntax:
fun(myvar:=out)
If I’m wrong, then you’d need some other syntax to say “pass myvar as a keyword
argument to the out parameter, but pass by name/by reference/whatever”. (You
can’t rely on the fact that out was special in the def, because you can’t see
what’s being called; it has to be something in the call syntax.) But I’m sure
you could invent something.
And whatever the syntax is, the semantics don’t require any existing value in
myvar.
So, how do you implement this? If you want intermediate assigns to be available
even if you exited by exception, you’d probably have to use cells. But I think
most languages with explicit outvar syntax don’t actually assign back until the
function returns normally. And that’s easy. Within the function, outvar is just
a plain old local. The RETURN_VALUE code sees that the code object has N
outvars, so it actually returns a tuple of (real_return_value, *outvars). (This
is an UnboundLocalError if any of them didn’t get assigned to, even if they
don’t get bound to caller names.) Then, on the caller side, the call was just
compiled to a CALL_FUNCTION and then a tuple extraction and a bunch of STORE_*
ops (ignoring any outvars that weren’t bound).
But, as I said at the top, I think this would be hard to teach and learn, and
confusing to read even after you’d learned it. And returning a namedtuple (or
taking a SimpleNamespace to fill, or just making it a mutating method of an
object…) does seem like a much better way to solve the UX problem, as you said._______________________________________________
Python-ideas mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at
https://mail.python.org/archives/list/[email protected]/message/656VPS6FK55HTC4THLJG5LIQ55ANUV22/
Code of Conduct: http://python.org/psf/codeofconduct/