
On Tue, Oct 20, 2009 at 4:04 AM, Nick Coghlan <ncoghlan@gmail.com> wrote:
Hmm. That's an interesting idea. I don't know enough about internals. It might be possible to do this with a decorator def foo(): a = 1 @allnonlocal def bar(): a = 2 bar() return a foo() => 2 However, even if possible, that would make everything nonlocal with no way to pick which ones. Here's another idea: def foo(): a = 1 b = 3 nonlocal def bar(): local b a = 2 b = 4 return (a,b) foo() => (2, 3) Prepending nonlocal to a function definition is equivalent to applying nonlocal to every variable referenced in that function unless the variable is declared local. For backward compatibility, the local statement would only be only recognized inside nonlocal functions. (Thus if you have a function that uses 'local' as a variable it would not need to be changed unless you decided to stick nonlocal in front of it.) Alternative syntax: def bar() nonlocal: --- Bruce http://www.vroospeak.com

Bruce Leban wrote:
I'd prefer: def foo(): a = 1 b = 3 def bar(): nonlocal * local b a = 2 b = 4 return (a,b) if a later 'local' can override an earlier 'nonlocal', or: def foo(): a = 1 b = 3 def bar(): local b nonlocal * a = 2 b = 4 return (a,b) if a 'nonlocal' can act as a catch-all for any names not previously mentioned.

On 20 Oct 2009, at 18:00 , MRAB wrote:
If you go that route, I'd suggest removing all the legacy stuff and just using "let" to create a new binding in the current scope: def foo(): let a = 1 let b = 3 def bar(): a = 2 let b = 4 bar() return (a, b) # returns (2, 3) Plus it allows the compiler to statically catch typos: def foo(): let some_very_complex_type = 42 def bar(): some_very_complex_typo = "oh noes" # not a new binding, no existing binding for that name => warning(*) bar() return some_very_complex_type You can even get "two in one" and use the keyword to create explicit scopes: def foo(): let foo="whatever", bar=42: do_something_with(foo, bar) return foo # warning, no foo in scope which would probably be useful mostly for code clarity purposes. *: warning, not error, because the programmer could be manipulating locals() directly, or something like that.

Masklinn wrote:
I'm with Stefan in laughing at the idea of someone never forgetting a variable declaration, and I've done a *lot* of programming in statically typed languages (and "let" really isn't that different from a type declaration). You're also omitting consideration of the ways *other* than assignment to bind a name in Python (i.e. def, with, except, for). Would those require an explicit let as well? If not, why single out assignment as a special case that requires an explicit declaration of "Yes, I really do want to create a new local here"? If yes... then whatever language you're dreaming of there, it is getting a really long way away from Python and giving up one of the major benefits of dynamic typing (i.e. no need for variable declarations). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

On 21 Oct 2009, at 13:50 , Nick Coghlan wrote:
it is getting a really long way away from Python
And I probably shouldn't have sent the previous mail that soon… Anyway on this specific quote, I do think `let` fits the Zen better than nothing/`global`/`nonlocal`: it's explicit rather than implicit (as far as scope goes), it's simple rather than complex (a single basic statement instead of 3 different forms depending on the exact case), it's more uniform (less special cases, if any), … I understand that you disagree, but I don't think the idea of `let` is "getting a long way away from Python".

On Wed, Oct 21, 2009 at 8:47 AM, Masklinn <masklinn@masklinn.net> wrote:
Sure. But that isn't the real choice. The need to write to outer variables is so rare that the vast majority of programs (let alone individual functions) never use global or nonlocal. So the real choice is whether to type out the redundant `let` or to just let the compiler infer it. (Well, unless you wanted to change the rules for let variables, to make deeper scoping and nesting more common.) -jJ

On Wed, Oct 21, 2009 at 8:47 AM, Masklinn <masklinn@masklinn.net> wrote:
def f(): def g():
First, I hardly think introducing a 'let' keyword as you suggest is pythonic. It's adding new syntax of a different flavor than the current syntax and breaking existing code. Why is it a different flavor? Because apparently you didn't notice that global and nonlocal are statements in their own right, not modifications of an assignment statement. So you're suggesting: global one nonlocal two let three = value It's also a different flavor because global says what it means, nonlocal says what it means and let says nothing about what it means. And breaking existing code without a damn good reason? I don't see that happening. It seems a bit inconsistent to me that global/nonlocal act differently with respect to reading and writing variables. That's a far worse problem than you're trying to solve. (See below.) But changing that would break a lot of code. So we live with it. My proposal (whether or not it's a good idea) wouldn't break any existing code. The new syntax proposed is currently invalid so can't appear in existing programs. It would add a new local statement that is only recognized in contexts that don't exist right now (and therefore can't break existing programs). The truth is that global and nonlocal add cognitive load to the person reading your code because they can't just read the one line to see what it's doing. This increases the burden on the developer to be clear in what they're writing. If my proposal allows us to decrease cognitive load on the reader, then it might be worth considering. As an aside, if instead of using the global/nonlocal statement we wrote: global.one = nonlocal.two Then the reader knows exactly what's global at the time it gets read. But I don't see that happening anytime soon given the preference for TOOWTDI and taking out the global/nonlocal statements would break too much code. And :-) we'd have to figure out what this statement means: foo = bar + global.bar + nonlocal.bar --- Bruce http://www.vroospeak.com print(i) i = 5 g()
f() 5
f3() 5

On Thu, 22 Oct 2009 08:57:15 -0700 Bruce Leban <bruce@leapyear.org> wrote:
I know there's a smiley, but it seems obvious. Further, it seems *useful*. If I have a local bar, a nonlocal bar and a global bar right now, I'm pretty much SOL for getting the global and local bars values (ok, I can get the global bar with some chicanery, but I can't see how to get the nonlocal bar). Making those namespaces explicit would seem to be as much of a win as making "self" explicit. Of course, you might argue that anyone who created three such variables named bar deserves to be barred, but... <mike -- Mike Meyer <mwm@mired.org> http://www.mired.org/consulting.html Independent Network/Unix/Perforce consultant, email for more information. O< ascii ribbon campaign - stop html mail - www.asciiribbon.org

Bruce Leban wrote:
I'd prefer: def foo(): a = 1 b = 3 def bar(): nonlocal * local b a = 2 b = 4 return (a,b) if a later 'local' can override an earlier 'nonlocal', or: def foo(): a = 1 b = 3 def bar(): local b nonlocal * a = 2 b = 4 return (a,b) if a 'nonlocal' can act as a catch-all for any names not previously mentioned.

On 20 Oct 2009, at 18:00 , MRAB wrote:
If you go that route, I'd suggest removing all the legacy stuff and just using "let" to create a new binding in the current scope: def foo(): let a = 1 let b = 3 def bar(): a = 2 let b = 4 bar() return (a, b) # returns (2, 3) Plus it allows the compiler to statically catch typos: def foo(): let some_very_complex_type = 42 def bar(): some_very_complex_typo = "oh noes" # not a new binding, no existing binding for that name => warning(*) bar() return some_very_complex_type You can even get "two in one" and use the keyword to create explicit scopes: def foo(): let foo="whatever", bar=42: do_something_with(foo, bar) return foo # warning, no foo in scope which would probably be useful mostly for code clarity purposes. *: warning, not error, because the programmer could be manipulating locals() directly, or something like that.

Masklinn wrote:
I'm with Stefan in laughing at the idea of someone never forgetting a variable declaration, and I've done a *lot* of programming in statically typed languages (and "let" really isn't that different from a type declaration). You're also omitting consideration of the ways *other* than assignment to bind a name in Python (i.e. def, with, except, for). Would those require an explicit let as well? If not, why single out assignment as a special case that requires an explicit declaration of "Yes, I really do want to create a new local here"? If yes... then whatever language you're dreaming of there, it is getting a really long way away from Python and giving up one of the major benefits of dynamic typing (i.e. no need for variable declarations). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

On 21 Oct 2009, at 13:50 , Nick Coghlan wrote:
it is getting a really long way away from Python
And I probably shouldn't have sent the previous mail that soon… Anyway on this specific quote, I do think `let` fits the Zen better than nothing/`global`/`nonlocal`: it's explicit rather than implicit (as far as scope goes), it's simple rather than complex (a single basic statement instead of 3 different forms depending on the exact case), it's more uniform (less special cases, if any), … I understand that you disagree, but I don't think the idea of `let` is "getting a long way away from Python".

On Wed, Oct 21, 2009 at 8:47 AM, Masklinn <masklinn@masklinn.net> wrote:
Sure. But that isn't the real choice. The need to write to outer variables is so rare that the vast majority of programs (let alone individual functions) never use global or nonlocal. So the real choice is whether to type out the redundant `let` or to just let the compiler infer it. (Well, unless you wanted to change the rules for let variables, to make deeper scoping and nesting more common.) -jJ

On Wed, Oct 21, 2009 at 8:47 AM, Masklinn <masklinn@masklinn.net> wrote:
def f(): def g():
First, I hardly think introducing a 'let' keyword as you suggest is pythonic. It's adding new syntax of a different flavor than the current syntax and breaking existing code. Why is it a different flavor? Because apparently you didn't notice that global and nonlocal are statements in their own right, not modifications of an assignment statement. So you're suggesting: global one nonlocal two let three = value It's also a different flavor because global says what it means, nonlocal says what it means and let says nothing about what it means. And breaking existing code without a damn good reason? I don't see that happening. It seems a bit inconsistent to me that global/nonlocal act differently with respect to reading and writing variables. That's a far worse problem than you're trying to solve. (See below.) But changing that would break a lot of code. So we live with it. My proposal (whether or not it's a good idea) wouldn't break any existing code. The new syntax proposed is currently invalid so can't appear in existing programs. It would add a new local statement that is only recognized in contexts that don't exist right now (and therefore can't break existing programs). The truth is that global and nonlocal add cognitive load to the person reading your code because they can't just read the one line to see what it's doing. This increases the burden on the developer to be clear in what they're writing. If my proposal allows us to decrease cognitive load on the reader, then it might be worth considering. As an aside, if instead of using the global/nonlocal statement we wrote: global.one = nonlocal.two Then the reader knows exactly what's global at the time it gets read. But I don't see that happening anytime soon given the preference for TOOWTDI and taking out the global/nonlocal statements would break too much code. And :-) we'd have to figure out what this statement means: foo = bar + global.bar + nonlocal.bar --- Bruce http://www.vroospeak.com print(i) i = 5 g()
f() 5
f3() 5

On Thu, 22 Oct 2009 08:57:15 -0700 Bruce Leban <bruce@leapyear.org> wrote:
I know there's a smiley, but it seems obvious. Further, it seems *useful*. If I have a local bar, a nonlocal bar and a global bar right now, I'm pretty much SOL for getting the global and local bars values (ok, I can get the global bar with some chicanery, but I can't see how to get the nonlocal bar). Making those namespaces explicit would seem to be as much of a win as making "self" explicit. Of course, you might argue that anyone who created three such variables named bar deserves to be barred, but... <mike -- Mike Meyer <mwm@mired.org> http://www.mired.org/consulting.html Independent Network/Unix/Perforce consultant, email for more information. O< ascii ribbon campaign - stop html mail - www.asciiribbon.org
participants (9)
-
Bruce Leban
-
Carl Johnson
-
Jim Jewett
-
Marcin 'Qrczak' Kowalczyk
-
Masklinn
-
Mike Meyer
-
MRAB
-
Nick Coghlan
-
Stefan Behnel