[Tim Delaney
My big concern here involves the:
if local(m = re.match(regexp, line)): print(m.group(0))
example. The entire block needs to be implicitly local for that to work - what happens if I assign a new name in that block?
I really don't know what you're asking there. Can you make it concrete? If, e.g., you're asking what happens if this appeared after the `print`: x = 3.14 then the answer is "the same as what would happen if `local` had not been used". We can't know what that is without context, though. Maybe x is global. Maybe x was declared nonlocal earlier. Maybe it's function-local. While it may be irrelevant to what you're asking, I noted just before: """ Time to note another subtlety: people don't _really_ want "a new scope" in Python. If they did, then _every_ name appearing in a binding context (assignment statement target, `for` target, ...) for the duration would vanish when the new scope ended. What they really want is a new scope with an implied "nonlocal" declaration for every name appearing in a binding context _except_ for the specific names they're effectively trying to declare as being "sublocal" instead. """ If by "new name" you mean that `x` didn't appear in any earlier line, then Python's current analysis would classify `x` as local to the current function (or as global if this is module-level code ...). That wouldn't change.
Also, what happens with:
if local(m = re.match(regexp1, line)) or local(m = re.match(regexp2, line)): print(m.group(0))
As is, if `local()` appears in an `if` or `while` expression, the scope extends to the end of the block construct. In that specific case, I'd expect to get a compile-time error, for attempting to initialize the same name more than once in the new scope. If the scope also encompasses associated `elif` statements, I'd instead expect local(m=...) in one of those to be treated as a re-initialization ;-) instead.
Would the special-casing of local still apply to the block?
As is, `local()` in an `if` or `while` expressions triggers deeply magical behavior, period.
Or would you need to do:
if local(m = re.match(regexp1, line) or re.match(regexp2, line)): print(m.group(0))
Yes, not to trigger magical behavior, but to avoid the compile-time error.
This might just be lack of coffee and sleep talking, but maybe new "scoping delimiters" could be introduced. Yes - I'm suggesting introducing curly braces for blocks, but with a limited scope (pun intended). Within a local {} block statements and expressions are evaluated exactly like they currently are, including branching statements, optional semi-colons, etc. The value returned from the block is from an explicit return, or the last evalauted expression.
a = 1 b = 2 c = local(a=3) * local(b=4)
c = local { a=3 } * local { b=4 }
c = local(a=3 , b=4, a*b)
c = local { a = 3 b = 4 a * b }
c = local(a=3, b=local(a=2, a*a), a*b)
c = local { a = 3 b = local(a=2, a*a)
I expect you wanted b = local{a=2; a*a} there instead (braces instead of parens, and semicolon instead of comma).
return a * b }
r1, r2 = local(D = b**2 - 4*a*c, sqrtD = math.sqrt(D), twoa = 2*a, ((-b + sqrtD)/twoa, (-b - sqrtD)/twoa))
r1, r2 = local { D = b**2 - 4*a*c sqrtD = math.sqrt(D) twoa = 2*a return ((-b + sqrtD)/twoa, (-b - sqrtD)/twoa) }
if local(m = re.match(regexp, line)): print(m.group(0))
if local { m = re.match(regexp, line) }: print(m.group(0))
OK, this is the only case in which you used it in an `if` or `while` expression. All the questions you asked of me at the start can be asked of this spelling too. You seemed to imply at the start that the right curly brace would always mark the end of the new scope. But if that's so, the `m` in `m.group()` has nothing to do with the `m` assigned to in the `local` block - _that_ scope ended before `print` was reached. So if you're not just trying to increase the level of complexity of what can appear in a local block, a fundamental problem still needs solving ;-) I suppose you could solve it like so: local { m = re.match(regexp, line) if m: print(m.group(0)) } but, besides losing the "shortcut", it would also mean something radically different if x = 3.14 appeared after the "print". Right? If a "local block" is taken seriously, then _all_ names bound inside it vanish when the block ends.
And a further implication:
a = lambda a, b: local(c=4, a*b*c)
a = lambda a, b: local { c = 4 return a * b * c }
If people do want a for-real "new scope" in Python, I certainly agree `local {...}` is far better suited for that purpose.