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
Copy file name to clipboardExpand all lines: docs/jep/12049-type-annotations.md
+14-11Lines changed: 14 additions & 11 deletions
Original file line number
Diff line number
Diff line change
@@ -239,7 +239,7 @@ Again, there are a couple mechanisms that could be used for this:
239
239
A decision we need to make is whether `ArrayAnnotation` and `ArrayInstance` should be the same or different objects. There is some precedent here; for example in the core Python language spec, `typing.Dict` and `typing.List` exist for the sake of annotation, while the built-in `dict` and `list` serve the purposes of instance checks.
240
240
However, `Dict` and `List` are [deprecated](https://peps.python.org/pep-0585/#implementation) in newer Python versions in favor of using `dict` and `list` for both annotation and instance checks.
241
241
242
-
####Following NumPy's lead
242
+
### Following NumPy's lead
243
243
244
244
In NumPy's case, `np.typing.NDArray` serves the purpose of type annotations, while `np.ndarray` serves the purpose of instance checks (as well as array type identity).
245
245
Given this, it may be reasonable to conform to NumPy's precedent and implement the following:
@@ -250,11 +250,11 @@ Given this, it may be reasonable to conform to NumPy's precedent and implement t
250
250
251
251
This might feel somewhat natural to NumPy power-users, however this trifurcation would likely be a source of confusion: the choice of which to use for instance checks and annotations is not immediately clear.
252
252
253
-
#### Unification
253
+
###Unifying instance checks and annotation
254
254
255
255
Another approach would be to unify type checking and annotation via override mechanisms mentioned above.
256
256
257
-
#####Option 1: Partial unification
257
+
### Option 1: Partial unification
258
258
A partial unification might look like this:
259
259
260
260
-`jax.Array` is the actual type of on-device arrays.
@@ -264,7 +264,7 @@ A partial unification might look like this:
264
264
In this approach, `jax.numpy.ndarray` would become a simple alias `jax.typing.Array` for backward compatibility.
265
265
266
266
267
-
#####Option 2: Full unification via overrides
267
+
#### Option 2: Full unification via overrides
268
268
Alternatively, we could opt for full unification via overrides:
269
269
270
270
-`jax.Array` is the actual type of on-device arrays.
@@ -273,7 +273,7 @@ Alternatively, we could opt for full unification via overrides:
273
273
274
274
Here, `jax.numpy.ndarray` would become a simple alias `jax.Array` for backward compatibility.
275
275
276
-
#####Option 3: Full unification via class hierarchy
276
+
#### Option 3: Full unification via class hierarchy
277
277
Finally, we could opt for full unification via restructuring of the class hierarchy and replacing duck-typing with OOP object hierarchies:
278
278
279
279
-`jax.Array` is the actual type of on-device arrays
@@ -283,7 +283,7 @@ Finally, we could opt for full unification via restructuring of the class hierar
283
283
Here `jnp.ndarray` could be an alias for `jax.Array`.
284
284
This final approach is in some senses the most pure, but it may be challenging from an OOP design standpoint (`Tracer`*is a*`Array`?).
285
285
286
-
#####Option 4: Parial unification via class hierarchy
286
+
#### Option 4: Parial unification via class hierarchy
287
287
We could appease OOP pedants by instead making `Tracer` and `Array` derive from a common `ArrayBase` base class:
288
288
289
289
-`jax.Array` is the actual type of on-device arrays
@@ -293,12 +293,15 @@ We could appease OOP pedants by instead making `Tracer` and `Array` derive from
293
293
Here `jnp.ndarray` would be an alias for `ArrayBase`.
294
294
This may be purer from an OOP perspective, but it reintroduces a bifurcation and the distinction between `Array` and `ArrayBase` for annotation and instance checks may become confusing.
295
295
296
-
#####Evaluation
296
+
#### Evaluation
297
297
298
-
There is no perfect option here, but from the point of view of the user, Options 2 and 3 arguably present the most clear user-facing API: `jax.Array` is all you need to know.
299
-
Option 3 (`Tracer` as a subclass of `Array`) is perhaps the purer approach, but on the other hand it would require `Tracer` objects to carry all the baggage of `Array` objects (data buffers, sharding, devices, etc.) For this reason, I (@jakevdp) believe that Option 2 presents the best path forward.
300
-
It offers the least confusing API for users and does not require any significant restructuring of our existing codepaths.
301
-
There is one minor technical hurdle involved; that is that `jax.Array` will be defined in C++ via pybind11, and pybind11 currently [does not support](https://github.com/pybind/pybind11/issues/2696) custom metaclasses required for overriding `__instancecheck__`; but I'd consider this a technical hurdle rather than a blocker.
298
+
Considering the overall strengths and weaknesses of each potential approach:
299
+
300
+
- From a user perspective, the unified approaches (options 2 and 3) are arguably best, because they remove the cognitive overhead involved in remembering which objects to use for instance checks or annotations: `jax.Array` is all you need to know
301
+
- Between Option 2 and Option 3, the purer (in an OOP sense) apporach is arguably Option 3 (`Tracer` as a subclass of `Array`), but in other senses it breaks the inheritance model, because it would require `Tracer` objects to carry all the baggage of `Array` objects (data buffers, sharding, devices, etc.)
302
+
- Option 2 is less pure in an OOP sense, but it aligns more closely with the spirit of how JAX is designed, with `Tracer` objects duck-typing as `Arrays`, and using mechanisms that Python provides to support this kind of duck typing. There is one minor technical hurdle involved; that is that `jax.Array` will be defined in C++ via pybind11, and pybind11 currently [does not support](https://github.com/pybind/pybind11/issues/2696) custom metaclasses required for overriding `__instancecheck__`; but I'd consider this a technical hurdle rather than a blocker.
303
+
304
+
With this in mind, we conclude that Option 2 presents the best path forward.
0 commit comments