Skip to content

Add sections on Assumptions and signatures #21

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions spec/API_specification/function_and_method_signatures.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Function and method signatures

Function signatures in this standard adhere to the following:

1. Positional parameters must be
[positional-only](https://www.python.org/dev/peps/pep-0570/) parameters.
Positional-only parameters have no externally-usable name. When a function
accepting positional-only parameters is called, positional arguments are
mapped to these parameters based solely on their order.

_Rationale: existing libraries have incompatible conventions, and using names
of positional parameters is not normal/recommended practice._

2. Optional parameters must be
[keyword-only](https://www.python.org/dev/peps/pep-3102/) arguments.

_Rationale: this leads to more readable code, and it makes it easier to
evolve an API over time by adding keywords without having to worry about
keyword order._

3. For functions that have a single positional array parameter, that parameter
is called `x`. For functions that have multiple array parameters, those
parameters are called `xi` with `i = 1, 2, ...` (i.e., `x1`, `x2`).

4. Type annotations are left out of the signatures themselves for readability;
they are added to the descriptions of individual parameters however. In code
which aims to adhere to the standard, adding type annotations is strongly
recommended.

A function signature and description will look like:

```
funcname(x1, x2, /, *, key1=-1, key2=None)

Parameters

x1 : array
description
x2 : array
description
key1 : int
description
key2 : Optional[str]
description

Returns

out : array
description
```

Method signatures will follow the same conventions and, modulo the addition of
`self`.
1 change: 1 addition & 0 deletions spec/API_specification/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ API specification
:caption: API specification
:maxdepth: 1

function_and_method_signatures
array_object
indexing
data_types
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
67 changes: 63 additions & 4 deletions spec/assumptions.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,74 @@
# Assumptions

## Hardware environments
## Hardware and software environments

No assumptions on a specific hardware environment are made. It must be possible
to create an array library adhering to this standard that runs (efficiently) on
a variety of different hardware: CPUs with different architectures, GPUs,
distributed systems and TPUs and other emerging accelerators.

The same applies to software environments: it must be possible to create an
array library adhering to this standard that runs efficiently independent of
what compilers, build-time or run-time execution environment, or distribution
and install method is employed. Parallel execution, JIT compilation, and
delayed (lazy) evaluation must all be possible.

## Software environments

The variety of hardware and software environments puts _constraints_ on choices
made in the API standard. For example, JIT compilers may require output dtypes
of functions to be predictable from input dtypes only rather than input values.


## Dependencies

The only dependency that's assumed in this standard is that on Python itself.
Python >= 3.8 is assumed, motivated by the use of positional-only parameters
(see [function and method signatures](API_specification/function_and_method_signatures.md)).

Importantly, array libraries are not assumed to be aware of each other, or of
a common array-specific layer. The [use cases](use_cases.md) do not require
such a dependency, and building and evolving an array library is easier without
such a coupling. Facilitation support of multiple array types in downstream
libraries is an important use case however, the assumed dependency structure
for that is:

![dependency assumptions diagram](_static/images/dependency_assumption_diagram.png)

Array libraries may know how to interoperate with each other, for example by
constructing their own array type from that of another library or by shared
memory use of an array (see [Data interchange mechanisms](design_topics/data_interchange.md)).
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everyone seemed happy with the assumptions in the call we discussed it in, 1.7 wks ago. The one comment on this data interchange was "can we just say now that this will be DLPack?". That should be in the section linked here, which is for another PR. So I'll go ahead and merge this as is.

This can be done without a dependency though - only adherence to a protocol is
enough.

Array-consuming libraries will have to depend on one or more array libraries.
That could be a "soft dependency" though, meaning retrieving an array library
namespace from array instances that are passed in, but not explicitly doing
`import arraylib_name`.


## Backwards compatibility

The assumption made during creation of this standard is that libraries are
constrained by backwards compatibility guarantees to their users, and are
likely unwilling to make significant backwards-incompatible changes for the
purpose of conforming to this standard. Therefore it is assumed that the
standard will be made available in a new namespace within each library, or the
library will provide a way to retrieve a module or module-like object that
adheres to this standard. See [How to adopt this API](purpose_and_scope.html#how-to-adopt-this-api)
for more details.


## Production code & interactive use

It is assumed that the primary use case is writing production code, for example
in array-consuming libraries. As a consequence, making it easy to ensure that
code is written as intended and has unambiguous semantics is preferred - and
clear exceptions must be raised otherwise.

## Interactive use & production code
It is also assumed that this does not significantly detract from the
interactive user experience. However, in case existing libraries differ in
behavior, the more strict version of that behavior is typically preferred. A
good example is array inputs to functions - while NumPy accepts lists, tuples,
generators, and anything else that could be turned into an array, most other
libraries only accept their own array types. This standard follows the latter choice.
It is likely always possible to put a thin "interactive use convenience layer"
on top of a more strict behavior.