Skip to content
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

PEP 695: Lazy evaluation, concrete scoping semantics, other changes #3122

Merged
merged 21 commits into from
May 8, 2023

Conversation

JelleZijlstra
Copy link
Member

@JelleZijlstra JelleZijlstra commented Apr 24, 2023

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:

I 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/

Copy link
Contributor

@erictraut erictraut left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Member

@gvanrossum gvanrossum left a 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.

pep-0695.rst Outdated Show resolved Hide resolved
pep-0695.rst Show resolved Hide resolved
pep-0695.rst Outdated Show resolved Hide resolved
pep-0695.rst Outdated Show resolved Hide resolved
- 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
@JelleZijlstra
Copy link
Member Author

@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.

pep-0695.rst Outdated Show resolved Hide resolved
pep-0695.rst Show resolved Hide resolved
pep-0695.rst Outdated Show resolved Hide resolved
@JelleZijlstra JelleZijlstra changed the title PEP 695: Changes proposed as a result of implementation work PEP 695: Lazy evaluation and other small changes Apr 26, 2023
@JelleZijlstra JelleZijlstra marked this pull request as ready for review April 26, 2023 16:27
@JelleZijlstra
Copy link
Member Author

Submitted python/steering-council#186 to the SC to approve these changes. Marking as "DO-NOT-MERGE" until the SC approves.

pep-0695.rst Outdated Show resolved Hide resolved
pep-0695.rst Outdated Show resolved Hide resolved
pep-0695.rst Show resolved Hide resolved
pep-0695.rst Outdated Show resolved Hide resolved
pep-0695.rst Outdated Show resolved Hide resolved
pep-0695.rst Outdated Show resolved Hide resolved
Copy link
Member

@gvanrossum gvanrossum left a 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!

pep-0695.rst Show resolved Hide resolved
@cdce8p
Copy link
Contributor

cdce8p commented Apr 26, 2023

Could you include the small AST change for TypeAlias.name here as well?

Couldn't comment inline unfortunately. It should be here:

TypeAlias(identifier name, typeparam* typeparams, expr value)

- TypeAlias(identifier name, typeparam* typeparams, expr value)
+ TypeAlias(expr name, typeparam* typeparams, expr value)

@JelleZijlstra
Copy link
Member Author

Pushed another change related to name mangling (I realized that the wording in the PEP would require severe complications in the symtable).

Copy link
Member

@gvanrossum gvanrossum left a 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.

@erictraut
Copy link
Contributor

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?

@JelleZijlstra
Copy link
Member Author

@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,)}

@JelleZijlstra JelleZijlstra changed the title PEP 695: Lazy evaluation and other small changes PEP 695: Lazy evaluation, concrete scoping semantics, other changes May 4, 2023
pep-0695.rst Outdated Show resolved Hide resolved
pep-0695.rst Outdated Show resolved Hide resolved
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
pep-0695.rst Outdated Show resolved Hide resolved
Copy link
Member

@markshannon markshannon left a 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?

pep-0695.rst Show resolved Hide resolved
pep-0695.rst Show resolved Hide resolved
@JelleZijlstra
Copy link
Member Author

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.

pep-0695.rst Outdated Show resolved Hide resolved
Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com>
@JelleZijlstra
Copy link
Member Author

The SC approved the proposed changes.

@JelleZijlstra JelleZijlstra merged commit 5cea9b5 into python:main May 8, 2023
@JelleZijlstra JelleZijlstra deleted the pep695change branch May 8, 2023 18:21
@hugovk
Copy link
Member

hugovk commented May 8, 2023

For reference: python/steering-council#186 (comment)

larryhastings pushed a commit to larryhastings/peps that referenced this pull request May 8, 2023
…ython#3122)

- 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
- Remove rejection of lambda lifting; that is the implementation we are using now
- Change the AST
- Change of direction on mangling
- More precise scoping rules

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com>
larryhastings added a commit that referenced this pull request May 16, 2023
* Improve PEP 649's description of its semantics.

* Stipulate that name resolution for annotations
  under 649 must be *identical* to stock semantics.
* *Don't* specify exactly the mechanism that conformant
  implementations must use to implement 649.  Instead,
  *do* describe how CPython might do it, but leave the
  actual details of how to implement 649 up to each
  language implementation.
* Incorporate Jelle's suggestion that the formats for
  inspect.get_annotations() be in an enum.IntEnum.

* Fix lint.

* PEP 693: Postpone 3.12.0b1 by two weeks (#3139)

* PEP 695: Lazy evaluation, concrete scoping semantics, other changes (#3122)

- 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
- Remove rejection of lambda lifting; that is the implementation we are using now
- Change the AST
- Change of direction on mangling
- More precise scoping rules

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com>

* Incorporate changes from feedback, mark Accepted.

* Fix PEP 12 header *order compliance*.  Wow.

* Fix Sphinx complaints.

* Make enum consistent, flesh out observed semantics.

* Add "Resolution" header, as pointed out by Hugo.

* Switch to other URL for Resolution header.

* Apply ``global_enum`` to ``inspect.AnnotationFormat``

* Final? text / semantics cleanup pass.

* "accept" -> "accepts".  Bettering my Englishes.

* Add new "post history" reflecting the updates.

* Update post history with all conversations, courtesy CAM!

Co-authored-by: C.A.M. Gerlach <CAM.Gerlach@Gerlach.CAM>

* Fix typo.  Thanks, Emily!

Co-authored-by: Emily Morehouse <emilyemorehouse@gmail.com>

* Add "Discussions-To" header.  Thanks, CAM!

Co-authored-by: C.A.M. Gerlach <CAM.Gerlach@Gerlach.CAM>

* Attempt to satisfy "validate-post-history" hook.

---------

Co-authored-by: Hugo van Kemenade <hugovk@users.noreply.github.com>
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com>
Co-authored-by: Adam Turner <9087854+aa-turner@users.noreply.github.com>
Co-authored-by: C.A.M. Gerlach <CAM.Gerlach@Gerlach.CAM>
Co-authored-by: Emily Morehouse <emilyemorehouse@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants