
On 28 February 2018 at 19:41, Chris Angelico <rosuav@gmail.com> wrote:
On Thu, Mar 1, 2018 at 3:30 AM, Paul Moore <p.f.moore@gmail.com> wrote:
Here's another equally untested piece of code:
[(-b + (sqrt(b*b - 4*a*c) as disc)) / (2*a), (-b - disc) / (2*a)]
Yeah, that's a good real world example. And IMO it hides the symmetry between the two expressions, so for me it's a good example of a case where there's a readability *disadvantage* with the proposed syntax.
I haven't dug into the implementation consequences of any of this at global scope. I know what parts of the code I need to look at, but my days have this annoying habit of having only 24 hours in them. Anyone got a bugfix for that? :|
I can give you daylight saving time and a few leap seconds, but that's more of a workaround than a fix :-)
Consider
x = 12 if (1 as x) == 1: def foo(): print(x) # Actually, you'd probably get a "Name used before definition" error here. # Would "global x" refer to x=12 or to the statement-local x (1)? # Would "nonlocal x" refer to the statement-local x? x = 13 return x print(foo())
Yeah, that's going to give UnboundLocalError, because inside foo(), x has been flagged as local. That's independent of the global scope changes.
I'd like to say that "global x" would catch the 12, but until I actually get around to implementing it, I'm not sure.
print(x) print(foo()) print(x)
Anything that executes after the 'if' exits should see x as 12. The temporary variable is completely gone at that point.
So simplifying x = 12 if (1 as x) == 1: def foo(): return x print(foo()) print(foo()) prints 1 12 Personally, I can't work out how to think about that in a way that isn't confusing :-( I gather from what you've said elsewhere that your current implementation uses a hidden name-mangled variable. IIRC, list comprehensions used something similar in the original implementation, but it resulted in weird consequences, and ultimately the implementation switched to a "proper" scoped semantics and implementation. I've no particular reason to think your implementation might suffer in the same way, but understanding the semantics in terms of an "assignment to a hidden variable" bothers me.
The most charitable thing I can say here is that the semantics are currently under-specified in the PEP :-)
Hah. This is why I started out by saying that this ONLY applies inside a function. Extending this to global scope (and class scope; my guess is that it'll behave the same as global) is something that I'm only just now looking into.
And yet, "only works within a function" is IMO an unacceptable limitation - so we need to look into the implications here.
So if, in the "in" expression list, you capture something, that thing will be visible all through the suite. Here's an example:
for item in (get_items() as items): print(item) print(items) print(items)
What actually happens is kinda this:
for item in (get_items() as items_0x142857): print(item) print(items_0x142857) del items_0x142857 print(items)
OK, so that explains why trying to write a closure over a variable introduced via "as" won't work. But I wouldn't want such a renaming to be mandated by the semantics, and I don't know how I'd explain the (implied) behaviour without insisting on a name mangling implementation, so I'm stuck here.
"What the current proof of concept implementation does" isn't useful anyway, but even ignoring that I'd prefer to see what it *does* rather than what it *compiles to*. But what needs to be documented is what the PEP *proposes* it does.
The current implementation matches my proposed semantics, as long as the code in question is all inside a function.
Understood. But I'd like the PEP to fully explain more of the intended semantics, *without* referring to the specific implementation. Remember, PyPy, Jython, IronPython, Cython, etc, will all have to implement it too.
But I can even break expression local names:
x = ((lambda: boom()) as boom) x()
It's possible that the "boom" is just my head exploding, not the interpreter. But I think I just demonstrated a closure over an expression-local name. For added fun, replace "x" with "boom"...
And this is why I am not trying for expression-local names. If someone wants to run with a competing proposal for list-comprehension-local names, sure, but I'm not in favour of that either. Expression-local is too narrow to be useful AND it still has the problems that statement-local has.
I've no idea how that would work under statement-local names either, though. boom = lambda: boom() boom() is just an infinite recursion. I'm less sure that the as version is. Or the alternative form ((lambda: boom()) as boom)() I know you can tell me what the implementation does - but I can't reason it out from the spec.
Thanks for the feedback! Keep it coming! :)
Ask and you shall receive :-)
If I take a razor and cut myself with it, it's called "self-harm" and can get me dinged for a psych evaluation. If I take a mailing list and induce it to send me hundreds of emails and force myself to read them all... there's probably a padded cell with my name on it somewhere.
You know, I'd be okay with that actually. Just as long as the cell has wifi.
lol. Have fun :-) Paul