Skip to content

Commit 9c47521

Browse files
authored
Suggest using lambdas for generic callables (#73)
1 parent addcb7a commit 9c47521

1 file changed

Lines changed: 90 additions & 7 deletions

File tree

pep.rst

Lines changed: 90 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -340,13 +340,18 @@ Here ``BaseTypedDict`` is defined as::
340340
class BaseTypedDict(typing.TypedDict):
341341
pass
342342

343-
But any typeddict would be allowed there. (Or, maybe we should allow ``dict``?)
343+
But any typeddict would be allowed there. (TODO: Or maybe we should
344+
allow ``dict``?)
344345

345346
This is basically a combination of
346347
"PEP 692 – Using TypedDict for more precise ``**kwargs`` typing"
347348
and the behavior of ``Unpack`` for ``*args``
348349
from "PEP 646 – Variadic Generics".
349350

351+
When inferring types here, the type checker should be **aggressive in
352+
inferring literal types when possible**. (TODO: Or maybe we need to
353+
make that configurable in the ``TypedDict`` erving as the bound?)
354+
350355
This is potentially moderately useful on its own but is being done to
351356
support processing ``**kwargs`` with type level computation.
352357

@@ -451,6 +456,8 @@ imported qualified or with some other name)
451456
# *[... for t in ...] arguments
452457
| <ident>[<variadic-type-arg> +]
453458

459+
| GenericCallable[<type>, lambda <args>: <type>]
460+
454461
# Type conditional checks are boolean compositions of
455462
# boolean type operators
456463
<type-bool> =
@@ -480,6 +487,9 @@ result type is a ``<type-bool>`` instead of a ``<type>``.)
480487
There are three core syntactic features introduced: type booleans,
481488
conditional types and unpacked comprehension types.
482489

490+
:ref:`"Generic callables" <generic-callable>` are also technically a
491+
syntactic feature, but are discussed as an operator.
492+
483493
Type booleans
484494
'''''''''''''
485495

@@ -672,6 +682,10 @@ Object creation
672682
similarly to ``NewProtocol`` but has different flags
673683

674684

685+
N.B: Currently we aren't proposing any way to create nominal classes
686+
or any way to make new *generic* types.
687+
688+
675689
.. _init-field:
676690

677691
InitField
@@ -709,7 +723,7 @@ as the ``Init`` field of the ``Member``.
709723
Annotated
710724
'''''''''
711725

712-
This could maybe be dropped?
726+
TODO: This could maybe be dropped if it doesn't seem implementable?
713727

714728
Libraries like FastAPI use annotations heavily, and we would like to
715729
be able to use annotations to drive type-level computation decision
@@ -746,17 +760,36 @@ The names, type, and qualifiers share getter operations with
746760
TODO: Should we make ``GetInit`` be literal types of default parameter
747761
values too?
748762

763+
.. _generic-callable:
764+
749765
Generic Callable
750-
''''''''''''''''
766+
""""""""""""""""
751767

752-
* ``GenericCallable[Vs, Ty]``: A generic callable. ``Vs`` are a tuple
768+
* ``GenericCallable[Vs, lambda <vs>: Ty]``: A generic callable. ``Vs`` are a tuple
753769
type of unbound type variables and ``Ty`` should be a ``Callable``,
754770
``staticmethod``, or ``classmethod`` that has access to the
755-
variables in ``Vs``
771+
variables in ``Vs`` via the bound variables in ``<vs>``.
772+
773+
For now, we restrict the use of ``GenericCallable`` to
774+
the type argument of ``Member`` (that is, to disallow its use for
775+
locals, parameter types, return types, nested inside other types,
776+
etc).
777+
778+
(This is a little unsatisfying. Rationale discussed :ref:`below
779+
<generic-callable-rationale>`.)
780+
781+
782+
(LAMBDA PART NOT IMPLEMENTED YET)
783+
784+
TODO: Decide if we have any mechanisms to inspect/destruct
785+
``GenericCallable``. Maybe can fetch the variable information and
786+
maybe can apply it to concrete types?
756787

757-
This is kind of unsatisfying but we at least need some way to return
758-
existing generic methods and put them back into a new protocol.
788+
Overloaded function types
789+
"""""""""""""""""""""""""
759790

791+
* ``Overloaded[*Callables]`` - An overloaded function type, with the
792+
underlying types in order.
760793

761794
String manipulation
762795
'''''''''''''''''''
@@ -1150,6 +1183,56 @@ I am proposing a fully new extended callable syntax because:
11501183
is a non starter)
11511184

11521185

1186+
.. _generic-callable-rationale:
1187+
1188+
Generic Callable
1189+
----------------
1190+
1191+
Consider a method with the following signature::
1192+
1193+
def process[T](self, x: T) -> T if IsSub[T, list] else list[T]:
1194+
...
1195+
1196+
The type of the method is generic, and the generic is bound at the
1197+
**method**, not the class. We need a way to represent such a generic
1198+
function both as a programmer might write it for a ``NewProtocol``.
1199+
1200+
One option that is somewhat appealing but doesn't work would be to use
1201+
unbound type variables and let them be generalized::
1202+
1203+
type Foo = NewProtocol[
1204+
Member[
1205+
Literal["process"],
1206+
Callable[[T], set[T] if IsSub[T, int] else T]
1207+
]
1208+
]
1209+
1210+
The problem is that this is basically incompatible with runtime
1211+
evaluation support, since evaluating the alias ``Foo`` will need to
1212+
evalaute the ``IsSub``, and so we will lose one side of the
1213+
conditional at least. Similar problems will happen when evaluating
1214+
``Members`` on a class with generic functions. By wrapping the body
1215+
in a lambda, we can delay evaluation in both of these cases. (The
1216+
``Members`` case of delaying evaluation works quite nicely for
1217+
functions with explicit generic annotations. For old-style generics,
1218+
we'll probably have to try to evaluate it and then raise an error when
1219+
we encounter a variable.)
1220+
1221+
1222+
The reason we suggest restricting the use of ``GenericCallable`` to
1223+
the type argument of ``Member`` is because full impredicative
1224+
polymorphism (where you can have generic type binding nested inside
1225+
types and you can instantiate type variables with other generic types)
1226+
is an big can of worms when combined with type inference (TODO: CITE).
1227+
While it would be nice to support, we don't want to
1228+
open that can of worms now.
1229+
1230+
1231+
The unbound type variable tuple is so that bounds and defaults and
1232+
``TypeVarTuple``-ness can be specified, though maybe we want to come
1233+
up with a new approach.
1234+
1235+
11531236
Backwards Compatibility
11541237
=======================
11551238

0 commit comments

Comments
 (0)