Skip to content

Syntax, semantics and use cases of forward references #34

@gvanrossum

Description

@gvanrossum

The best proposal we have for forward references is:

  • If a type annotation must reference a class that is not yet defined at the time the annotation is evaluated at run time, the annotation (or a part thereof) can be enclosed in string quotes, and the type checker will resolve this.

This typically occurs when defining a container class where the class itself appears in the signature of some of its methods; the (global) name for the class is not defined until after the body of the class definition has been executed. (In some cases there may be multiple mutually recursive classes, so a shorthand for "this class" isn't really enough.)

A typical example is:

T = TypeVar('T')
class Node(Generic[T]):
    def add_left(self, node: 'Node[T]'):
        self.left = node

Note that the entire annotation expression 'Node[T]' is quoted, not just the class name Node (because 'Node'[T] makes no sense).

The question I'm trying to ask here is whether there is a reasonable limit to the complexity of the syntax that we must support inside string quotes. And if not, whether we may need to invent some other way to specify forward references. For example, something like this has been proposed:

T = TypeVar('T')
Node = ForwardRef('Node')
class Node(Generic[T]):
    def add_left(self, node: Node[T]):
        self.left = node

A related question is whether the __annotations__ dict should be "patched" to reference the intended class, or whether it is up to the code introspecting __annotations__ to interpret forward references (and if the latter, what kind of support typing.py should export to help).

I've got a feeling that the ForwardRef() approach makes things a little easier for the runtime support, at the cost of slight verbosity. The question is how common forward references really are (apart from stubs for builtin/stdlib container).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions