erictraut / cpython

The Python programming language
https://www.python.org/
Other
2 stars 0 forks source link

Lazy evaluation and PEP 649 #11

Open JelleZijlstra opened 1 year ago

JelleZijlstra commented 1 year ago

My current prototype evaluates TypeVar bounds eagerly:

>>> class Foo[FooT: x]: pass
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <generic parameters of Foo>
NameError: name 'x' is not defined

I haven't implemented type aliases yet, but the specification in the PEP says they should also be evaluated eagerly.

This means that you'd have to use quoted annotations in order to use forward references in these contexts (for example, for a class generic over a TypeVar bound to itself; or for mutually recursive generic aliases).

Given that PEP 649 is likely to be the future of annotations in general, this is problematic. PEP 649 should generally eliminate the need to quote annotations, but here we're introducing new contexts where quoted annotations are unavoidable.

Should we instead use a PEP 649-like mechanism to delay evaluation of TypeVar bounds and type alias values?

erictraut commented 1 year ago

I'm of two minds here. The bound is not a type annotation. It is an argument passed to the constructor of the TypeVar. The same is true for constraints and PEP 696-style defaults. Using the traditional TypeVar constructor, you need to quote these expressions if you want to use forward references, and that won't change with PEP 649.

On the other hand, it would be nice to eliminate the need for quoted forward references in another place where they are currently required.

Will deferred execution work in this context? For example:

class Foo[T]:
    class Bar: ...
    class Baz[S: Bar]: ...

If the expression Bar is executed in a deferred manner, will your proposed implementation be able to evaluate it correctly? I think the answer is no because the deferred execution mechanism relies on lambda lifting, and Bar isn't visible to the lambda's scope.

JelleZijlstra commented 1 year ago

If the expression Bar is executed in a deferred manner, will your proposed implementation be able to evaluate it correctly? I think the answer is no because the deferred execution mechanism relies on lambda lifting, and Bar isn't visible to the lambda's scope.

My current prototype does not, but Larry's technique in PEP 649 (https://peps.python.org/pep-0649/#other-modifications-to-existing-objects) would cover this case.

Depending on that technique would mean a dependency on the implementation of PEP 649 though, which will make it even harder to get it into 3.12.