Skip to content

Commit 8652c99

Browse files
authored
More motivating examples in the PEP (#65)
1 parent 0f4d4c0 commit 8652c99

1 file changed

Lines changed: 66 additions & 0 deletions

File tree

pep.rst

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

257319
Specification 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

Comments
 (0)