You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Grammar specification of the extensions to the type language.
27
+
We introduce a ``Param`` type the contains all the information about a function param::
21
28
22
-
It's important that there be a clearly specified type language for the type-level computation---we can't just be using some poorly specified subset of all Python.
29
+
class Param[N: str | None, T, Q: ParamQuals = typing.Never]:
And then, we can represent the type of a function like::
35
+
def func(
36
+
a: int,
37
+
/,
38
+
b: int,
39
+
c: int = 0,
40
+
*args: int,
41
+
d: int,
42
+
e: int = 0,
43
+
**kwargs: int
44
+
) -> int:
45
+
...
46
+
47
+
as (we are omiting the ``Literal`` in places)::
48
+
49
+
Callable[
50
+
[
51
+
Param[None, int],
52
+
Param["b", int],
53
+
Param["c", int, "default"],
54
+
Param[None, int, "*"],
55
+
Param["d", int, "keyword"],
56
+
Param["e", int, Literal["default", "keyword"]],
57
+
Param[None, int, "**"],
58
+
],
59
+
int,
60
+
]
23
61
24
-
# TODO: Big Q: what should be an error and what should return Never?
25
62
63
+
---------
64
+
Rationale
65
+
---------
66
+
We need extended callable support, in order to inspect and produce callables via type-level computation. mypy supports `extended callables <https://mypy.readthedocs.io/en/stable/additional_features.html#extended-callable-types>`__ but they are deprecated in favor of callback protocols.
67
+
68
+
69
+
Unfortunately callback protocols don't work well for type level computation. (They probably could be made to work, but it would require a separate facility for creating and introspecting *methods*, which wouldn't be any simpler.)
70
+
71
+
I am proposing a fully new extended callable syntax because:
72
+
1. The ``mypy_extensions`` functions are full no-ops, and we need real runtime objects
73
+
2. They use parentheses and not brackets, which really goes against the philosophy here
74
+
3. We can make an API that more nicely matches what we are going to do for inspecting members
75
+
(We could introduce extended callables that closely mimic the ``mypy_extensions`` version though, if something new is a non starter)
76
+
4. I thought they were missing support for something but may have been wrong. They can handle positional-only.
It's important that there be a clearly specified type language for the type-level computation---we can't just be using some poorly specified subset of all Python.
26
84
27
85
::
28
86
@@ -63,46 +121,70 @@ It's important that there be a clearly specified type language for the type-leve
63
121
64
122
``type-for(T)`` is a parameterized grammar rule, which can take different types. Not sure if we actually need this though---now it is only used for Any/All.
65
123
66
-
---
124
+
-----
125
+
126
+
==============
127
+
Type operators
128
+
==============
67
129
68
130
* ``GetArg[T, Base, Idx: Literal[str]]`` - returns the type argument number ``Idx`` to ``T`` when interpreted as ``Base``, or ``Never`` if it cannot be. (That is, if we have ``class A(B[C]): ...``, then ``GetArg[A, B, 0] == C`` while ``GetArg[A, A, 0] == Never``).
131
+
N.B: *Unfortunately* ``Base`` must be a proper class, *not* a protocol. So, for example, ``GetArg[Ty, Iterable, 0]]`` to get the type of something
132
+
iterable *won't* work. This is because we can't do protocol checks at runtime in general.
69
133
Special forms unfortunately require some special handling: the arguments list of a ``Callable`` will be packed in a tuple, and a ``...`` will become ``SpecialFormEllipsis``.
70
134
71
135
72
136
* ``GetArgs[T, Base]`` - returns a tuple containing all of the type arguments of ``T`` when interpreted as ``Base``, or ``Never`` if it cannot be.
73
137
* ``FromUnion[T]`` - returns a tuple containing all of the union elements, or a 1-ary tuple containing T if it is not a union.
74
138
75
139
76
-
# TODO: NewProtocol needs a way of doing bases also...
77
-
# TODO: New TypedDict setup
140
+
------------------------------
141
+
Object inspection and creation
142
+
------------------------------
78
143
79
144
* ``NewProtocol[*Ps: Member]``
80
145
146
+
81
147
* ``Members[T]`` produces a ``tuple`` of ``Member`` types.
82
-
* ``Member[N: Literal[str], T, Q: Quals, D]``
148
+
* ``Member[N: Literal[str], T, Q: MemberQuals, D]`` - ``N`` is the name, ``T`` is the type, ``Q`` is a union of qualifiers, ``D`` is the defining class of the member
149
+
* ``MemberQuals = Literal['ClassVar', 'Final']`` - ``MemberQuals`` is the type of "qualifiers" that can apply to a member; currently ClassVar and Final
150
+
151
+
TODO: How do we indicate ``@classmethod`` and ``@staticmethod``; should we have wrapper types for them. (That *kind of* matches reality...)
152
+
153
+
TODO: What do we do about decorators in general, *at runtime*...
83
154
84
-
# These names are too long -- but we can't do ``Type`` !!
85
-
# Kind of want to do the *longer* ``MemberName``
155
+
We also have helpers for extracting those names; they are all definable in terms of ``GetArg``.
156
+
(These names are too long -- but we can't do ``Type``. I kind of want to do the *longer* ``MemberName``?)
86
157
87
158
* ``GetName[T: Member]``
88
159
* ``GetType[T: Member]``
89
160
* ``GetQuals[T: Member]``
90
161
* ``GetDefiner[T: Member]``
91
-
* Could we also put the defining type there??
92
162
93
-
---
163
+
* ``NewProtocolWithBases[Bases, Ps: tuple[Member]]`` - A variant that allows specifying bases too. (UNIMPLEMENTED)
164
+
165
+
* ``NewTypedDict[*Ps: Member]`` -- TODO: Needs fleshing out; will work similarly to ``NewProtocol`` but has different flags
166
+
94
167
95
168
* ``GetAttr[T, S: Literal[str]]``
96
169
TODO: How should GetAttr interact with descriptors/classmethod? I am leaning towards it should apply the descriptor...
97
170
98
-
* ``Length[T: tuple]`` - get the length of a tuple as an int literal (...or ``Literal[None]`` if it is unbounded)
171
+
172
+
----
173
+
174
+
* ``Length[T: tuple]`` - get the length of a tuple as an int literal (or ``Literal[None]`` if it is unbounded)
175
+
176
+
----
99
177
100
178
String manipulation operations for string Literal types.
101
179
We can put more in, but this is what typescript has.
102
180
``Slice`` and ``Concat`` are a poor man's literal template.
103
181
We can actually implement the case functions in terms of them and a
Two possibilities for creating parameterized functions/types. They are kind of more syntax than functions exactly. I like the lambda one more.
200
+
* ``NewParameterized[V, Ty]`` - ``V`` should be a ``TypeVar`` (ugh!) and ``Ty`` should be a ``Callable`` or a ``NewProtocol`` or some such.
201
+
* ``NewParameterized[lambda v: Ty]`` - The lambda could take multiple params, and introduce multiple variables. The biggest snag is how to specify bounds; one option is via default arguments.
Can we actually implement Is (IsSubtype) at runtime in a satisfactory way?
210
+
Can we actually implement Is (IsSubtype) at runtime in a satisfactory way? (PROBABLE DECISION: external library *and* restricted checking.)
126
211
- There is a lot that needs to happen, like protocols and variance inference and callable subtyping (which might require matching against type vars...)
127
212
Jukka points out that lots of type information is frequently missing at runtime too: attributes are frequently unannotated and
128
213
@@ -139,10 +224,7 @@ Can we actually implement Is (IsSubtype) at runtime in a satisfactory way?
139
224
140
225
It's unsatisfying, though.
141
226
142
-
2.
143
-
DECISION: quals string literals seems fine
144
-
145
-
How do we deal with modifiers? ClassVar, Final, Required, ReadOnly
227
+
2. How do we deal with modifiers? ClassVar, Final, Required, ReadOnly (DECISION: quals string literals seems fine)
146
228
- One option is to treat them not as types by as *modifiers* and have them
147
229
in a separate field where they are a union of Literals.
148
230
So ``x: Final[ClassVar[int]]`` would appear in ``Attrs`` as
@@ -156,8 +238,7 @@ How do we deal with modifiers? ClassVar, Final, Required, ReadOnly
156
238
157
239
158
240
3.
159
-
How do we deal with Callables? We need to support extended callable syntax basically.
160
-
Or something like it.
241
+
How do we deal with Callables? We need to support extended callable syntax basically. Or something like it. (ANSWER: ``Param``)
161
242
162
243
4.
163
244
What do we do about ``Members`` on built-in types? ``typing.get_type_hints(int)`` returns ``{}`` but mypy will not agree!
@@ -170,9 +251,10 @@ Polymorphic callables? How do we represent their type and how do we construct th
170
251
What does TS do here? - TS has full impredactive polymorphic functions. You can do System F stuff. *But* trying to do type level operations on them seems to lose track of the polymorphism: the type vars will get instantiated with ``unknown``.
171
252
172
253
6.
173
-
Want to be graceful at runtime, since **many** classes don't have full annotations.
254
+
What operations should be error and what should return Never?
255
+
174
256
175
-
=====
257
+
----
176
258
177
259
This proposal is less "well-typed" than typescript... (Well-kinded, maybe?)
178
260
Typescript has better typechecking at the alias definition site:
0 commit comments