'const' and 'require' statements

Hello, I am new here but am itching with an idea. Here are two separate ideas but they are related so they shall both be presented at the same time. The first idea is for a 'const' statement for declaring constant names. Its syntax would be: 'const' identifier '=' expression The expression would be restricted to result in an immutable object such as 17, "green", or (1,2,3). The compiler would effectively replace any use of the identifier with this expression when seen. Some examples of constants might include: const ST_MODE = 0 const FontName = "Ariel" const Monday = 1 const Tuesday = Monday + 1 # may use previously defined const in expression. Compiler will fold constants (hopefully) Constant names would be limited in scope. A constant defined in a function would only have a life to the end of the function, for instance. Now why should there be such a syntax if the existing language already has a mechanism for effectively declaring constants, which it does? First, it opens possibilities for the compiler to do things like more constant folding and generally producing more efficient code. Second, since the compiler substitutes for the name at compile time, there is no chance for the name to be stepped on at run-time. Third, ideas such as PEP 3103 could be re-visited. One of the problems in PEP 3103 was that so often constants are represented by names and those names may be changed and/or the constant values in those names are not known until run-time. Constant names are fine but of limited use if they may only be used within the module they are declared in. This brings up the second idea of a 'require' statement. The import statement of Python is executed at run-time. This creates a disconnect between modules at compile time (which is a good thing) but gives the compiler no hint as to how to produce better code. What I propose is a 'require' statement with almost exactly the same syntax as the import and from statements but with the keyword 'require' substituted for 'module'. The word require was chosen because the require declaration from the BLISS language helped inspire this idea. C minded people might prefer using a word such as include be used instead. What the require statement would do is cause the module to be read in by the compiler and compiled when the statement is parsed. The contents of a required module could be restricted to only be const statements in order to avoid the many headaches this would produce. Examples: require font_data from stat_constants require ST_MODE from weekdays require * In the first example, the name 'font_data' would be a constant module to the compiler. An expression such as font_data.FontName would at compile-time reference the constant name FontName from the font_data module and substitute for it. In the second example, the constant name ST_MODE is added to the current scope. In the third example, all constant names defined in the module (except those with a '_' prefix) are added to the current scope. Since the names added are constant names and not variable names, it is OK to use require * at the function scope level. In order to help compatibility with existing uses and to avoid declaring constants twice, a require statement could use a 'as *' to both include constant names and assign them to a module's dictionary. For example, the file stat.py might do something like: require stat_constants as * This would add all the constant names defined in the stat_constants module and place them in the stat module's dictionary. For instance, if there is the line in stat_constant.py: const ST_MODE = 0 Then for stat.py the compiler will act as if it saw: ST_MODE = 0 Well, those are my two bits of ideas. Thank you, James Harding

"Harding, James" <james.d.harding@siemens.com> writes:
The first idea is for a 'const' statement for declaring constant names.
Do you have some concrete Python code which would clearly be improved by this proposal?
Its syntax would be:
'const' identifier '=' expression
The expression would be restricted to result in an immutable object such as 17, "green", or (1,2,3). The compiler would effectively replace any use of the identifier with this expression when seen. Some examples of constants might include:
const ST_MODE = 0 const FontName = "Ariel" const Monday = 1 const Tuesday = Monday + 1 # may use previously defined const in expression. Compiler will fold constants (hopefully)
So, the compiler will “replace any use of the identifier with” the constant value. const ST_MODE = 0 const ST_FILENAME = "foo" const ST_RECURSIVE = True name_prefix = "ST_" foo = globals().get(name_prefix + "MODE") bar = globals().get(name_prefix + "FILENAME") baz = globals().get(name_prefix + "RECURSIVE") What do you expect the compiler to do in the above code? -- \ “Airports are ugly. Some are very ugly. Some attain a degree of | `\ ugliness that can only be the result of a special effort.” | _o__) —Douglas Adams, _The Long Dark Tea-Time of the Soul_, 1988 | Ben Finney

On 18Jan2013 14:37, Ben Finney <ben+python@benfinney.id.au> wrote: | "Harding, James" | <james.d.harding@siemens.com> writes: | > Its syntax would be: | > 'const' identifier '=' expression | > | > The expression would be restricted to result in an immutable object | > such as 17, "green", or (1,2,3). The compiler would effectively replace | > any use of the identifier with this expression when seen. Some examples | > of constants might include: | > | > const ST_MODE = 0 | > const FontName = "Ariel" | > const Monday = 1 | > const Tuesday = Monday + 1 # may use previously defined const | > in expression. Compiler will fold constants (hopefully) | | So, the compiler will “replace any use of the identifier with” the | constant value. | | const ST_MODE = 0 | const ST_FILENAME = "foo" | const ST_RECURSIVE = True | | name_prefix = "ST_" | foo = globals().get(name_prefix + "MODE") | bar = globals().get(name_prefix + "FILENAME") | baz = globals().get(name_prefix + "RECURSIVE") | | What do you expect the compiler to do in the above code? Personally I'd expect the compiler to produce essentially the same code it does now with stock Python. After all, name_prefix isn't a const. But under his proposal I'd expect the compiler to be _able_ to produce inlined constant results for bare, direct uses of ST_MODE etc. If I'd written his proposal I'd have probably termed these things "bind-once", generating names that may not be rebound. They would still need to be carefully placed if the compiler were to have the option of constant folding i.e. they're need to be outside function and class definitions, determinable from static analysis. Just comments, not endorsement:-) -- Cameron Simpson <cs@zip.com.au>

On 18 January 2013 04:28, Cameron Simpson <cs@zip.com.au> wrote:
If I'd written his proposal I'd have probably termed these things "bind-once", generating names that may not be rebound. They would still need to be carefully placed if the compiler were to have the option of constant folding i.e. they're need to be outside function and class definitions, determinable from static analysis.
A few thoughts along the same lines: 1. Global lookups are not likely to be the performance bottleneck in any real code, so constant folding is not going to be a particular benefit. 2. The idea of names that can't be rebound isn't particularly Pythonic (given that things like private class variables aren't part of the language) 3. Constants that can't be imported from another module aren't much use, and yet if they can be imported you have real problems enforcing the non-rebindability. Consider: import my_consts print(my_consts.A_VALUE) # Presumably a constant value, but obviously the compiler can't inline it... my_consts.A_VALUE = 12 # The language has no chance to prevent this without completely changing module semantics Named values are obviously a good thing, but I see little benefit, and a lot of practical difficulty, with the idea of "enforced const-ness" in Python. Paul.

On Fri, Jan 18, 2013 at 7:01 PM, Paul Moore <p.f.moore@gmail.com> wrote:
Named values are obviously a good thing, but I see little benefit, and a lot of practical difficulty, with the idea of "enforced const-ness" in Python.
FWIW, people can play whatever games they like by injecting arbitrary objects into sys.modules.
class Locked: ... def __setattr__(self, attr, value): ... raise AttributeError("Rebinding not permitted") ... def __delattr__(self, attr): ... raise AttributeError("Deletion not permitted") ... attr1 = "Hello" ... attr2 = "World" ... sys.modules["example"] = Locked import example example.attr1 'Hello' example.attr2 'World' example.attr2 = "Change" example.attr2 = "World" sys.modules["example"] = Locked() import example example.attr1 'Hello' example.attr2 'World' example.attr2 = "Change" Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in __setattr__ AttributeError: Rebinding not permitted
The import system is even defined to expressly permit doing this in a *module's own code* by replacing "sys.module[__name__]" with a different object. So, any such proposal needs to be made with the awareness that anyone that *really* wants to do this kind of thing already can, but they don't. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On 18/01/13 12:52, Harding, James wrote:
Hello,
I am new here but am itching with an idea. Here are two separate ideas but they are related so they shall both be presented at the same time.
The first idea is for a 'const' statement for declaring constant names. Its syntax would be:
'const' identifier '=' expression
The expression would be restricted to result in an immutable object
What is the purpose of this restriction? I would like to see the ability to prevent rebinding or unbinding of names, with no restriction on the value. If that is useful (and I think it is), then it is useful for mutable objects as well as immutable.
such as 17, "green", or (1,2,3). The compiler would effectively replace any use of the identifier with this expression when seen.
Is that the driving use-case for your suggestion? Compile-time efficiency? If so, then I suspect that you're on the wrong track. As I understand it, the sort of optimizations that PyPy can perform at runtime are far more valuable than this sort of constant substitution. There are also complications that need to be carefully thought about. For example, in Python today, you can be sure that this assertion will always pass: k = ("Some value", "Another value") # for example x = k y = k assert x is y # this always passes, no matter the value of k But if k is a const, it will fail, because the lines "x = k" and "y = k" will be expanded at compile time: x = ("Some value", "Another value") y = ("Some value", "Another value") assert x is y # not guaranteed to pass So Python would have to intern every const, not just do a compile-time substitution. And that will have runtime consequences. Another question: what happens if the constant expression can't be evaluated until runtime? x = random.random() const k = x + 1 y = k - 1 What value should the compiler substitute for y?
Constant names would be limited in scope. A constant defined in a function would only have a life to the end of the function, for instance.
I don't think that makes sense. Since you're talking about something known to the compiler, it is meaningless to talk about the life of the constant *at runtime*. Consider: def f(n): const k = ("something", "or", "other") if n == 0: return k else: return k[n:] This will compile to the byte-code equivalent of: def f(n): if n == 0: return ("something", "or", "other") else: return ("something", "or", "other")[n:] I recommend you run that function through dis.dis to see what it will be compiled to. In the compiled code, there are two calls to the LOAD_CONST byte-code. The literal ("something", "or", "other") needs to be compiled into the byte-code, and so it will exist for as long as the function exists, not just until the function exits.
Now why should there be such a syntax if the existing language already has a mechanism for effectively declaring constants, which it does?
I dispute that Python has a mechanism for effectively declaring constants. It has a *convention* for declaring constants, and hoping that neither you, the developer, nor the caller, accidentally (or deliberately) rebind that pseudo-constant. -- Steven

On Thu, Jan 17, 2013 at 8:52 PM, Steven D'Aprano <steve@pearwood.info>wrote:
On 18/01/13 12:52, Harding, James wrote:
The first idea is for a 'const' statement for declaring constant names. Its syntax would be:
'const' identifier '=' expression
The expression would be restricted to result in an immutable object
What is the purpose of this restriction?
I would like to see the ability to prevent rebinding or unbinding of names, with no restriction on the value. If that is useful (and I think it is), then it is useful for mutable objects as well as immutable.
Java has a keyword 'final' which means a variable must be bound exactly once. It is an error if it is bound more than once or not bound at all, or read before it is initialized. For example, if a class has a final non-static field foo, then the constructor *must* set foo. A final value may be immutable. http://en.wikipedia.org/wiki/Final_(Java) This catches double initialization errors among other things. I don't know if final belongs in Python, but I'd find that more useful than const. --- Bruce http://bit.ly/yearofpuzzles

On Fri, Jan 18, 2013 at 3:52 PM, Steven D'Aprano <steve@pearwood.info> wrote:
Another question: what happens if the constant expression can't be evaluated until runtime?
x = random.random() const k = x + 1
y = k - 1
What value should the compiler substitute for y?
That should be disallowed. In the declaration of a constant, you have to use only what can be handled by the constants evaluator. As a rule of thumb, it'd make sense to be able to use const with anything that could safely be evaluated by ast.literal_eval. As to the issues of rebinding, I'd just state that all uses of a particular named constant evaluate to the same object, just as would happen if you used any other form of name binding. I don't have the post to hand, but wasn't there a project being discussed recently that would do a lot of that work automatically? ChrisA

Compiler-enforced immutability is one of those really hard problems which, if you manage to do flexibly and correctly, would be an academically publishable result, not something you hack into the interpreter over a weekend. If you go the dumb-and-easy route, you end up with a simple "sub this variable with constant" thing, which isn't very useful (what about calculated constants?) If you go the slightly-less-dumb route, you end up with some mini-language to work with these `const` values, which has some operations but not the full power of python. This basically describes C Macros, which I don't think you'd want to include in python! If you go the "full python" route, you basically branch into two possibilities. - enforcement of `const` as part of the main program. If you do it hackily, you end up with C++'s `const` or Java's `final` declaration. Neither of these really make the object (and all of its contents!) immutable. If you want to do it properly, this would involve some sort of effect-tracking-system. This is really hard. - multi-stage computations, so the program is partially-evaluated at "compile" time and the `const` sections computed. This is also really hard. Furthermore, if you want to be able to use bits of the standard library in the early stages (you probably do, e.g. for things like min, max, len, etc.) either you'd need to manually start annotating huge chunks of the standard library to be available at "compile" time (a huge undertaking) or you'll need an effect-tracking-system to do it for you. In any case, either you get a crappy implementation that nobody wants (C Macros) something that doesn't really give the guarantees you'd hope for (java final/c++ const) or you would have a publishable result w.r.t. either effect-tracking (!) or multi-stage computations (!!!). Even though it is very easy to describe the idea (it just stops it from changing, duh!) and how it would work in a few trivial cases, doing it properly will likely require some substantial theoretical breakthroughs before it can actually happen. On Thu, Jan 17, 2013 at 10:31 PM, Chris Angelico <rosuav@gmail.com> wrote:
On Fri, Jan 18, 2013 at 3:52 PM, Steven D'Aprano <steve@pearwood.info> wrote:
Another question: what happens if the constant expression can't be evaluated until runtime?
x = random.random() const k = x + 1
y = k - 1
What value should the compiler substitute for y?
That should be disallowed. In the declaration of a constant, you have to use only what can be handled by the constants evaluator. As a rule of thumb, it'd make sense to be able to use const with anything that could safely be evaluated by ast.literal_eval.
As to the issues of rebinding, I'd just state that all uses of a particular named constant evaluate to the same object, just as would happen if you used any other form of name binding.
I don't have the post to hand, but wasn't there a project being discussed recently that would do a lot of that work automatically?
ChrisA _______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas

On Fri, Jan 18, 2013 at 9:06 AM, Haoyi Li <haoyi.sg@gmail.com> wrote:
Compiler-enforced immutability is one of those really hard problems which, if you manage to do flexibly and correctly, would be an academically publishable result, not something you hack into the interpreter over a weekend.
If you go the dumb-and-easy route, you end up with a simple "sub this variable with constant" thing, which isn't very useful (what about calculated constants?)
If you go the slightly-less-dumb route, you end up with some mini-language to work with these `const` values, which has some operations but not the full power of python. This basically describes C Macros, which I don't think you'd want to include in python!
If you go the "full python" route, you basically branch into two possibilities.
- enforcement of `const` as part of the main program. If you do it hackily, you end up with C++'s `const` or Java's `final` declaration. Neither of these really make the object (and all of its contents!) immutable. If you want to do it properly, this would involve some sort of effect-tracking-system. This is really hard.
- multi-stage computations, so the program is partially-evaluated at "compile" time and the `const` sections computed. This is also really hard. Furthermore, if you want to be able to use bits of the standard library in the early stages (you probably do, e.g. for things like min, max, len, etc.) either you'd need to manually start annotating huge chunks of the standard library to be available at "compile" time (a huge undertaking) or you'll need an effect-tracking-system to do it for you.
In any case, either you get a crappy implementation that nobody wants (C Macros) something that doesn't really give the guarantees you'd hope for (java final/c++ const) or you would have a publishable result w.r.t. either effect-tracking (!) or multi-stage computations (!!!).
Even though it is very easy to describe the idea (it just stops it from changing, duh!) and how it would work in a few trivial cases, doing it properly will likely require some substantial theoretical breakthroughs before it can actually happen.
On Thu, Jan 17, 2013 at 10:31 PM, Chris Angelico <rosuav@gmail.com> wrote:
On Fri, Jan 18, 2013 at 3:52 PM, Steven D'Aprano <steve@pearwood.info> wrote:
Another question: what happens if the constant expression can't be evaluated until runtime?
x = random.random() const k = x + 1
y = k - 1
What value should the compiler substitute for y?
That should be disallowed. In the declaration of a constant, you have to use only what can be handled by the constants evaluator. As a rule of thumb, it'd make sense to be able to use const with anything that could safely be evaluated by ast.literal_eval.
As to the issues of rebinding, I'd just state that all uses of a particular named constant evaluate to the same object, just as would happen if you used any other form of name binding.
I don't have the post to hand, but wasn't there a project being discussed recently that would do a lot of that work automatically?
ChrisA _______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas
_______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas
As has already been pointed out, syntax to allow compile-time optimisations doesn't really make much sense in python, especially considering the optimisations Pypy already carries out. Some sort of "finalise" option may be somewhat useful (although I can't say I've ever needed it). To avoid adding a new keyword it could be implementer as a function, e.g. finalise("varname") or finalise(varname="value"). In a class, this would actually be quite easy to implement by simply replacing the class dict with a custom dict designed to restrict writing to finalised names. I haven't ever tried changing the globals dict type, but I imagine it would be possible, or at least possible to to provide a method to change it. I haven't thought through all the implications of doing it this way, but I'd rather see something like this than a new "const" keyword. David

On Fri, Jan 18, 2013 at 5:22 PM, David Townshend <aquavitae69@gmail.com> wrote:
As has already been pointed out, syntax to allow compile-time optimisations doesn't really make much sense in python, especially considering the optimisations Pypy already carries out. Some sort of "finalise" option may be somewhat useful (although I can't say I've ever needed it). To avoid adding a new keyword it could be implementer as a function, e.g. finalise("varname") or finalise(varname="value"). In a class, this would actually be quite easy to implement by simply replacing the class dict with a custom dict designed to restrict writing to finalised names. I haven't ever tried changing the globals dict type, but I imagine it would be possible, or at least possible to to provide a method to change it. I haven't thought through all the implications of doing it this way, but I'd rather see something like this than a new "const" keyword.
While you won't see module level support (beyond the ability to place arbitrary classes in sys.modules), this is already completely possible through the descriptor protocol (e.g. by creating read-only properties). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On Fri, Jan 18, 2013 at 10:08 AM, Nick Coghlan <ncoghlan@gmail.com> wrote:
On Fri, Jan 18, 2013 at 5:22 PM, David Townshend <aquavitae69@gmail.com> wrote:
As has already been pointed out, syntax to allow compile-time optimisations doesn't really make much sense in python, especially considering the optimisations Pypy already carries out. Some sort of "finalise" option may be somewhat useful (although I can't say I've ever needed it). To avoid adding a new keyword it could be implementer as a function, e.g. finalise("varname") or finalise(varname="value"). In a class, this would actually be quite easy to implement by simply replacing the class dict with a custom dict designed to restrict writing to finalised names. I haven't ever tried changing the globals dict type, but I imagine it would be possible, or at least possible to to provide a method to change it. I haven't thought through all the implications of doing it this way, but I'd rather see something like this than a new "const" keyword.
While you won't see module level support (beyond the ability to place arbitrary classes in sys.modules), this is already completely possible through the descriptor protocol (e.g. by creating read-only properties).
Cheers, Nick.
-- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
True. I was going for something which might work in modules too, but module-level descriptors would probably be a more consistent approach anyway. This is actually something I have needed in the past, and got around it by putting a class in sys.modules. Maybe finding a neat way to write module-level descriptors would be more useful, and cover the same use case as consts? David

On Fri, Jan 18, 2013 at 7:38 PM, David Townshend <aquavitae69@gmail.com> wrote:
True. I was going for something which might work in modules too, but module-level descriptors would probably be a more consistent approach anyway. This is actually something I have needed in the past, and got around it by putting a class in sys.modules. Maybe finding a neat way to write module-level descriptors would be more useful, and cover the same use case as consts?
I think putting class objects in sys.modules *is* the way to get "module level" descriptors. The fact it feels like a hack is a positive in my book - techniques that are "always dubious, but sometimes necessary" *should* feel like hacks, so people stay away from them until they run out of other options :) Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On 18 January 2013 05:22, David Townshend <aquavitae69@gmail.com> wrote:
As has already been pointed out, syntax to allow compile-time optimisations doesn't really make much sense in python, especially considering the optimisations Pypy already carries out. Some sort of "finalise" option may be somewhat useful (although I can't say I've ever needed it). To avoid adding a new keyword it could be implementer as a function, e.g. finalise("varname") or finalise(varname="value"). In a class, this would actually be quite easy to implement by simply replacing the class dict with a custom dict designed to restrict writing to finalised names. I haven't ever tried changing the globals dict type, but I imagine it would be possible, or at least possible to to provide a method to change it. I haven't thought through all the implications of doing it this way, but I'd rather see something like this than a new "const" keyword.
Yes - changing a module's (or object that stands for a module :-) ) dict type does work [1] - which would allow for a "module decorator" to change it. So, the functionality from Java's "final" and others can be had in Python today, with a small set of "module decorator" utilities. Now, do I think such a thing should go in the standard library? -0 for that. [1] - http://stackoverflow.com/questions/13274916/python-imported-module-is-none/1...
David

On Fri, Jan 18, 2013 at 5:06 PM, Haoyi Li <haoyi.sg@gmail.com> wrote:
Compiler-enforced immutability is one of those really hard problems which, if you manage to do flexibly and correctly, would be an academically publishable result, not something you hack into the interpreter over a weekend.
If you go the dumb-and-easy route, you end up with a simple "sub this variable with constant" thing, which isn't very useful (what about calculated constants?)
If you go the slightly-less-dumb route, you end up with some mini-language to work with these `const` values, which has some operations but not the full power of python. This basically describes C Macros, which I don't think you'd want to include in python!
If you go the "full python" route, you basically branch into two possibilities.
- enforcement of `const` as part of the main program. If you do it hackily, you end up with C++'s `const` or Java's `final` declaration. Neither of these really make the object (and all of its contents!) immutable. If you want to do it properly, this would involve some sort of effect-tracking-system. This is really hard.
- multi-stage computations, so the program is partially-evaluated at "compile" time and the `const` sections computed. This is also really hard. Furthermore, if you want to be able to use bits of the standard library in the early stages (you probably do, e.g. for things like min, max, len, etc.) either you'd need to manually start annotating huge chunks of the standard library to be available at "compile" time (a huge undertaking) or you'll need an effect-tracking-system to do it for you.
In any case, either you get a crappy implementation that nobody wants (C Macros) something that doesn't really give the guarantees you'd hope for (java final/c++ const) or you would have a publishable result w.r.t. either effect-tracking (!) or multi-stage computations (!!!).
Even though it is very easy to describe the idea (it just stops it from changing, duh!) and how it would work in a few trivial cases, doing it properly will likely require some substantial theoretical breakthroughs before it can actually happen.
As James noted, lack of a good answer to this problem is part of the reason Python doesn't have a switch/case statement [1,2] (only part, though). We already have three interesting points in time where evaluation can happen in Python code: - compile time (evaluation of literals, including tuples of literals) - function definition time (evaluation of decorator expressions, annotations and default arguments, along with decorator invocation) - execution time (normal execution time - in the case of functions, function definition time occurs during the execution time of the containing scope) We know from experience with default arguments that people find evaluation at function definition time *incredibly* confusing, because it means a data value is shared across functions. You can try to limit this by saying "immutable values only", but then you run into the problem where dynamic name lookups mean only literals can be considered truly constant, and those are *already* evaluated (and sometimes folded together) at compile time:
def f(): ... return 2 * 3 ... dis.dis(f) 2 0 LOAD_CONST 3 (6) 3 RETURN_VALUE
(The constant folding in CPython isn't especially clever, but that's an implementation issue - the language spec already *allows* such folding, we just don't always detect when it's possible). So, once you allow name lookups, the question then becomes what namespace they run in. If you say "the containing namespace" then you get a few interesting consequences: 1. We're in the same, already known to be confusing, territory as function default arguments 2. The behaviour of the new construct at module and class level will necessarily be different to that at function level 3. Quality of error messages and tracebacks will be a potential issue for debugging 4. When two of these constructs exist in the same scope, is the later one allowed to refer to the earlier one? Now we get to the meat of James's suggestion, and while I think it's a pretty decent take on the "multi-stage evaluation" proposal, it still runs afoul of many of the same problems past proposals [3] have struggled with: 1. Name binding operations other than assignment (e.g. import, function and class definitions) 2. Handling of name binding in nested functions 3. Handling of references to previous early evaluation operations 4. Breaking expectations regarding dynamic modification of module globals 5. Finding a good keyword is hard - suitable terms are either widely used as variable names, or have too much misleading baggage from other languages I can alleviate the concerns about making other components available at compile time though - if this construct was defined appropriately, Python would be able to happily import, compile and execute other modules during a suitable "pre-execution" phase. The real kicker though, is that, after all that work, you'll have to ask two questions: 1. Does this change help Python users write more readable code? 2. Does this change help JIT-compiled Python code (e.g. in PyPy) run faster? (PyPy's JIT can often identify near-constants and move their calculation out of any frequently executed code paths) If the answer to that turns out to be "No to both, but it will help CPython, which has no JIT, run some manually annotated code faster", then it's a bad idea (it's not an *obviously* bad idea - just one that is a lot trickier than it may first appear). Cheers, Nick. [1] http://www.python.org/dev/peps/pep-0275/ [2] http://www.python.org/dev/peps/pep-3103/ [3] https://encrypted.google.com/search?q=site%3Amail.python.org%20inurl%3Apytho... -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
participants (11)
-
Ben Finney
-
Bruce Leban
-
Cameron Simpson
-
Chris Angelico
-
David Townshend
-
Haoyi Li
-
Harding, James
-
Joao S. O. Bueno
-
Nick Coghlan
-
Paul Moore
-
Steven D'Aprano