From 8e90359cff60b0b97cc2cf8e4256fa39dca123ac Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Tue, 8 Sep 2020 22:27:21 +0100 Subject: [PATCH 1/4] Add a description of how to adopt the API Ref discussion from 20 Aug. The thing I left out of this text is a global dispatch. The last point made on that was: ... there is some inherent difficulties. Local dispatch is the more straightforward approach, but difficulties arise when you want a particular function to use a particular backend implementation. and I wasn't quite sure if that concern is valid - maybe I'm missing some details. If the "you" in there is the library author, then they should just ignore the whole API standard namespace and just do `import lib_I_want; lib_I_want.`. If it is the end user, then they normally would pass in an array of the right type that would control this. So the one case I see where the concern applies is if there is some function that does _not_ take any array input, but creates arrays internally _and_ the default array type for that creation is somehow undesirable. That seems a bit unlikely. --- spec/API_specification/index.rst | 10 +++++++- spec/purpose_and_scope.md | 42 ++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/spec/API_specification/index.rst b/spec/API_specification/index.rst index 86873453d..266fb96fa 100644 --- a/spec/API_specification/index.rst +++ b/spec/API_specification/index.rst @@ -1,3 +1,5 @@ +.. _api-specification: + API specification ================= @@ -16,4 +18,10 @@ API specification elementwise_functions statistical_functions searching_functions - linear_algebra_functions \ No newline at end of file + linear_algebra_functions + + +.. _api-versioning: + +TODO: add `__array_api_version__` (or similar) version here, and the way to + retrieve it - see https://github.com/data-apis/workgroup/issues/24 diff --git a/spec/purpose_and_scope.md b/spec/purpose_and_scope.md index 7e00a4e27..d1c81aa6c 100644 --- a/spec/purpose_and_scope.md +++ b/spec/purpose_and_scope.md @@ -29,6 +29,48 @@ For guidance on how to read and understand the type annotations included in this ## How to adopt this API +Most (all) existing array libraries will find something in this API standard +that is incompatible with a current implementation, and that they cannot +change due to backwards compatibility concerns. Therefore we expect that each +of those libraries will want to offer a standard-compliant API in a _new +namespace_. The question then becomes: how does a user access this namespace? + +The simplest method is: document the import to use to directly access the +namespace (e.g. `import package_name.array_api`). This has two issues though: + +1. Array-consuming libraries that want to support multiple array libraries + then have to explicitly import each library. +2. It is difficult to _version_ the array API standard implementation (see + :ref:`api-versioning`). + +To address both issues, a uniform method must be provided by a conforming +implementation to access the API namespace, namely a function: + +``` +mod = x.__array_namespace__(api_version='2020.10') +``` + +TBD: what should the naming convention be for the namespace (`mod` above)? + +.. note:: + + This is inspired by [NEP 37](https://numpy.org/neps/nep-0037-array-module.html#how-to-use-get-array-module), + however it avoids adding a dependency on NumPy or having to provide a + separate package just to do `get_array_module(x)` + + NEP 37 is still in flux (it was just accepted by JAX and TensorFlow on an + experimental basis), and it's possible that that should be accepted instead. + + TBD: a decision must be made on this topic before a first version of the + standard can become final. We prefer to delay this decision, to see how + NEP 37 adoption will work out. + +The `mod` namespace must contain the array object and all functionality +specified in :ref:`api-specification`. It may contain other functionality, +however it is recommended not to add other functions or objects, because that +may make it harder for users to write code that will work with multiple array +libraries. + * * * From fd63c5d1d4a9cfd3c3a9da34daa15b8c26d68635 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Sun, 13 Sep 2020 21:02:22 +0100 Subject: [PATCH 2/4] Change the namespace convention to `xp` (borrowed from CuPy) --- spec/purpose_and_scope.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/spec/purpose_and_scope.md b/spec/purpose_and_scope.md index d1c81aa6c..58c64c50c 100644 --- a/spec/purpose_and_scope.md +++ b/spec/purpose_and_scope.md @@ -47,11 +47,9 @@ To address both issues, a uniform method must be provided by a conforming implementation to access the API namespace, namely a function: ``` -mod = x.__array_namespace__(api_version='2020.10') +xp = x.__array_namespace__(api_version='2020.10') ``` -TBD: what should the naming convention be for the namespace (`mod` above)? - .. note:: This is inspired by [NEP 37](https://numpy.org/neps/nep-0037-array-module.html#how-to-use-get-array-module), @@ -65,7 +63,7 @@ TBD: what should the naming convention be for the namespace (`mod` above)? standard can become final. We prefer to delay this decision, to see how NEP 37 adoption will work out. -The `mod` namespace must contain the array object and all functionality +The `xp` namespace must contain the array object and all functionality specified in :ref:`api-specification`. It may contain other functionality, however it is recommended not to add other functions or objects, because that may make it harder for users to write code that will work with multiple array From 3a36812290329876befa5916b6a1bfde14d44f18 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Sun, 13 Sep 2020 21:05:15 +0100 Subject: [PATCH 3/4] Clarify that using an API version to retrieve the namespace is optional --- spec/purpose_and_scope.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/spec/purpose_and_scope.md b/spec/purpose_and_scope.md index 58c64c50c..e1336fc1c 100644 --- a/spec/purpose_and_scope.md +++ b/spec/purpose_and_scope.md @@ -46,6 +46,13 @@ namespace (e.g. `import package_name.array_api`). This has two issues though: To address both issues, a uniform method must be provided by a conforming implementation to access the API namespace, namely a function: +``` +xp = x.__array_namespace__() +``` + +The function must take one keyword, `api_version=None`, to make it possible to +request a specific API version: + ``` xp = x.__array_namespace__(api_version='2020.10') ``` From 8ecf1e9c960abb5667f9c515409bf27ffab894bd Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Thu, 22 Oct 2020 13:03:33 +0100 Subject: [PATCH 4/4] Minor textual clarification to address review comment. --- spec/purpose_and_scope.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/purpose_and_scope.md b/spec/purpose_and_scope.md index e1336fc1c..ce98bef04 100644 --- a/spec/purpose_and_scope.md +++ b/spec/purpose_and_scope.md @@ -43,14 +43,14 @@ namespace (e.g. `import package_name.array_api`). This has two issues though: 2. It is difficult to _version_ the array API standard implementation (see :ref:`api-versioning`). -To address both issues, a uniform method must be provided by a conforming -implementation to access the API namespace, namely a function: +To address both issues, a uniform way must be provided by a conforming +implementation to access the API namespace, namely a method on the array object: ``` xp = x.__array_namespace__() ``` -The function must take one keyword, `api_version=None`, to make it possible to +The method must take one keyword, `api_version=None`, to make it possible to request a specific API version: ```