On Tue, Oct 20, 2009 at 4:04 AM, Nick Coghlan <ncoghlan@gmail.com> wrote:
The difference lies in the fact that in C, object references are non-local by default - you have to declare them explicitly in the current scope to make them local.
Accordingly, I find the idea of a new function-like construct where all non-argument variable references are nonlocal by default to be a potentially interesting one.
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:
On Tue, Oct 20, 2009 at 4:04 AM, Nick Coghlan <ncoghlan@gmail.com <mailto:ncoghlan@gmail.com>> wrote:
The difference lies in the fact that in C, object references are non-local by default - you have to declare them explicitly in the current scope to make them local.
Accordingly, I find the idea of a new function-like construct where all non-argument variable references are nonlocal by default to be a potentially interesting one.
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:
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:
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.
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:
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
No, please. Why would you want to require so much typing for the most common case? And how often would you forget to declare a variable that way? Stefan
On 20 Oct 2009, at 19:55 , Stefan Behnel wrote:
Masklinn 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 No, please. Why would you want to require so much typing for the most common case? Simpler, clearer, non ambiguous. As opposed to the current scheme of scope inference which is ambiguous and error prone.
Also, nothing would prevent combining variable creations if need be. Not like this will ever happen anyway, but a guy can dream.
And how often would you forget to declare a variable that way?
Never.
On 20 Oct 2009, at 20:23 , Stefan Behnel wrote:
Masklinn wrote:
On 20 Oct 2009, at 19:55 , Stefan Behnel wrote:
And how often would you forget to declare a variable that way?
Never. :) Had a good laugh on that one, thanks! Why? It's a very simple process: "I'm creating a binding" matches to a let. Plus the runtime could easily warn you in the rare cases where you'd forgotten a let.
I can assure you it's not a very difficult habit to pick.
Masklinn wrote:
On 20 Oct 2009, at 20:23 , Stefan Behnel wrote:
Masklinn wrote:
On 20 Oct 2009, at 19:55 , Stefan Behnel wrote:
And how often would you forget to declare a variable that way?
Never. :) Had a good laugh on that one, thanks! Why? It's a very simple process: "I'm creating a binding" matches to a let. Plus the runtime could easily warn you in the rare cases where you'd forgotten a let.
I can assure you it's not a very difficult habit to pick.
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:
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?
No.
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"? Because in all those other cases, the fact that you "really do want to create a new local here" is part of the statement's semantics. Why repeat it?
giving up one of the major benefits of dynamic typing (i.e. no need for variable declarations). I don't see that as a benefit of dynamic typing (in fact I don't even see that as relevant to dynamic typing, some dynamically typed languages have implicit locals declaration, others have explicit locals — and scope — declaration). And even if it were a benefit of dynamic typing, it's hardly a major one, and it's one with a bunch of drawbacks as scope inference tends to be unreliable and messy (leading to the need for `global` and `nonlocal` in Python).
2009/10/21 Masklinn <masklinn@masklinn.net>:
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"?
Because in all those other cases, the fact that you "really do want to create a new local here" is part of the statement's semantics. Why repeat it?
Actually in the other cases an existing variable is assigned if it was already defined in the current scope, or it is defined if it was not - like in the assignment syntax. -- Marcin Kowalczyk qrczak@knm.org.pl
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:
... I do think `let` fits the Zen better than nothing/`global`/`nonlocal`: ... instead of 3 different forms depending on the exact
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:
... I do think `let` fits the Zen better than nothing/`global`/`nonlocal`: ... instead of 3 different forms depending on the exact
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
def f2(): def g(): i = 5 g() print(i)
f2() Traceback (most recent call last): File "<pyshell#35>", line 1, in <module> f2() File "<pyshell#34>", line 5, in f2 print(i) NameError: global name 'i' is not defined
def f3(): i = None def g(): nonlocal i i = 5 g() print(i)
f3() 5
On Thu, 22 Oct 2009 08:57:15 -0700 Bruce Leban <bruce@leapyear.org> wrote:
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
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
2009/10/20 Masklinn:
def foo(): let a = 1 let b = 3 def bar(): a = 2 let b = 4 bar() return (a, b) # returns (2, 3)
This is all fantasy, but what is your proposal when this happens: def foo(): let a = 1 stuff stuff let a = 2 #Oops, forgot about already declaring it! I also imagine that you won't allow a bare "let a"? Or does it just set itself to None? — Carl
On 21 Oct 2009, at 12:03 , Carl Johnson wrote:
This is all fantasy, but what is your proposal when this happens:
def foo(): let a = 1 stuff stuff let a = 2 #Oops, forgot about already declaring it!
It could be a noop, but I think a warning (or an error if scopes are statically checked) would be a smarter idea, make the programmer aware that something weird's happening.
I also imagine that you won't allow a bare "let a"? Or does it just set itself to None? There's not much sense in a bare `let a` imo, if you want it to be nothing, just write `let a = None`.
participants (9)
-
Bruce Leban
-
Carl Johnson
-
Jim Jewett
-
Marcin 'Qrczak' Kowalczyk
-
Masklinn
-
Mike Meyer
-
MRAB
-
Nick Coghlan
-
Stefan Behnel