-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
PEP 695: Lazy evaluation, concrete scoping semantics, other changes #3122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
erictraut
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
gvanrossum
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some preliminary comments while I have this freshly in my head.
- Lazy evaluation means that referencing a later type variable works at runtime - Disallow walrus in TypeVar bounds, and also disallow yield/yield from/await in the same contexts
|
@erictraut @gvanrossum I pushed a few more changes; please take a look. I am also considering adding more information about the implementation technique I'm currently using (a dummy immediately evaluated function, which I just learned is "lambda lifting"), but I'm not sure we need to specify that in the PEP. |
|
Submitted python/steering-council#186 to the SC to approve these changes. Marking as "DO-NOT-MERGE" until the SC approves. |
gvanrossum
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for taking care to explain all these details clearly!
|
Could you include the small AST change for Couldn't comment inline unfortunately. It should be here: Line 802 in 63a594f
- TypeAlias(identifier name, typeparam* typeparams, expr value)
+ TypeAlias(expr name, typeparam* typeparams, expr value) |
|
Pushed another change related to name mangling (I realized that the wording in the PEP would require severe complications in the symtable). |
gvanrossum
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 on the mangling change.
|
Does the mangling change mean that inner scopes cannot refer to that type parameter without generating a runtime exception? class Foo[__T]:
def method(self, val: __T): # Does this work?
x: __T = val # Does this work? |
|
@erictraut yes, that will work. (Though note that the annotation within the function will always work without a runtime exception, because annotations on locals are never evaluated.) The name is mangled at both the definition site and all usage sites within the class. This was quite easy to implement: python/cpython@bd49622. The PEP previously proposed not mangling the TypeVar names. That would require deep changes to the symtable to track whether a name refers to a TypeVar. The new proposed approach is more consistent with the rest of the language: names that are syntactically within a class are always mangled. I think there are very few ways the mangling is even visible to user code. The only way I can think of is this: >>> class A: pass
...
>>> class Foo[__T](print(locals()) or A): pass
...
{'_Foo__T': __T, '.generic_base': typing.Generic[__T], '.type_params': (__T,)} |
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
markshannon
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely an improvement.
It still isn't clear to me which of the def695 "functions" exist to provide scopes for type variables, and which are to support lazy evaluation. Are the semantics of both identical?
Yes, they have identical semantics. Let me push something to make that explicit. |
Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com>
|
The SC approved the proposed changes. |
|
For reference: python/steering-council#186 (comment) |
This adds some clarifications and changes that I ran into while implementing the PEP.
The most important change is that TypeVar bounds and type alias values are lazily evaluated using PEP 649-like semantics. This will make the language more consistent once type annotations are evaluated using PEP 649.
Prior discussion:
__type_params__attribute replacing__type_variables__: Semantics of__type_variables__erictraut/cpython#10, Clarification in the choice of __type_variables__ vs __type_param(eter)?s__ erictraut/cpython#8yieldetc.: Prohibit yield, yield from, await, walrus in aliases and bounds? erictraut/cpython#13I am marking this as draft for now in case I run into more things that need to be changed. We'll have to ask the SC for approval, but hopefully these changes are not controversial.
cc @erictraut
📚 Documentation preview 📚: https://pep-previews--3122.org.readthedocs.build/