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/

Reply via email to