@@ -253,6 +253,68 @@ futher special casing, typechecker plugins, hardcoded support, etc.
253253
254254(Example code for implementing this :ref: `below <init-impl >`.)
255255
256+ More powerful decorator typing
257+ ------------------------------
258+
259+ The typing of decorator functions has long been a pain point in python
260+ typing. The situation was substantially improved by the introducing of
261+ ``ParamSpec `` in :pep: `PEP 612 <612 >`, but a number of patterns remain
262+ unsupported:
263+
264+ * Adding/removing/modifying a keyword parameter
265+ * Modifying a variable number of parameters -- XXX: check how well TypeVarTuple does this
266+
267+ This proposal will cover those cases.
268+
269+ XXX: Ehhhhhh the generic situation could be bad for some of it? For
270+ partial certainly, I think, which otherwise we can almost do.
271+
272+ NumPy-style broadcasting
273+ ------------------------
274+
275+ One of the motivations for the introduction of ``TypeVarTuple `` in
276+ :pep: `PEP 646 <646 >` is to represent the shapes of multi-dimensional
277+ arrays, such as::
278+
279+ x: Array[float, L[480], L[640]] = Array()
280+
281+ The example in the that PEP shows how ``TypeVarTuple `` can be used to
282+ make sure that both sides of an arithmetic operation having matching
283+ shapes. Most multi-dimensional array libraries, however, also support
284+ [#broadcasting ]_, which allows the mixing of differently shaped data.
285+ With this PEP, we can define a ``Broadcast[A, B] `` type alias, and
286+ then use it as a return type::
287+
288+ class Array[DType, *Shape]:
289+ def __add__[*Shape2](
290+ self,
291+ other: Array[DType, *Shape2]
292+ ) -> Array[DType, *Broadcast[tuple[*Shape], tuple[*Shape2]]]:
293+ raise BaseException
294+
295+ (The somewhat clunky syntax of wrapping the ``TypeVarTuple `` in
296+ another ``tuple `` is because typecheckers currently disallow having
297+ two ``TypeVarTuple `` arguments. A possible improvement would be to
298+ allow writing the bare (non-starred or ``Unpack ``-ed) variable name to
299+ mean its interpretation as a tuple.)
300+
301+ We can then do::
302+
303+ a1: Array[float, L[4], L[1]]
304+ a2: Array[float, L[3]]
305+ a1 + a2 # Array[builtins.float, Literal[4], Literal[3]]
306+
307+ b1: Array[float, int, int]
308+ b2: Array[float, int]
309+ b1 + b2 # Array[builtins.float, int, int]
310+
311+ err1: Array[float, L[4], L[2]]
312+ err2: Array[float, L[3]]
313+ # err1 + err2 # E: Broadcast mismatch: Literal[2], Literal[3]
314+
315+
316+ TODO: Link the implementation
317+
256318
257319Specification of Needed Preliminaries
258320=====================================
@@ -496,6 +558,8 @@ Basic operators
496558 if it cannot be. (That is, if we have ``class A(B[C]): ... ``, then
497559 ``GetArg[A, B, 0] == C `` while ``GetArg[A, A, 0] == Never ``).
498560
561+ Negative indexes work in the usual way.
562+
499563 N.B: *Unfortunately * ``Base `` must be a proper class, *not * a
500564 protocol. So, for example, ``GetArg[Ty, Iterable, 0]] `` to get the
501565 type of something iterable *won't * work. This is because we can't do
@@ -1162,6 +1226,8 @@ Footnotes
11621226.. _#prisma : https://www.prisma.io/
11631227.. _#prisma-example : https://github.com/prisma/prisma-examples/tree/latest/orm/express
11641228.. _#qb-test : https://github.com/geldata/typemap/blob/main/tests/test_qblike_2.py
1229+ .. [#broadcasting ] http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html
1230+
11651231
11661232 Copyright
11671233=========
0 commit comments