On Thursday, Apr 25, 2019 at 9:45 PM, Marten van Kerkwijk <m.h.vankerkwijk@gmail.com> wrote:
It seems we are adding to the wishlist!  I see four so far:
1. Exposed in API, can be overridden with __array_ufunc__
2. One that converts everything to ndarray (or subclass); essentially the current implementation;
3. One that does asduckarray
4. One that assumes all arguments are arrays.

Maybe handiest would be if there is a method to coerce all relevant arguments with a function of one's choice? I.e., in the example of Stephan, one would have
if function in JUST_COERCE:
    coerced_args, coerced_kwargs = function.__coerce__(np.asanyarray, *args, **kwargs)
    return function.__implementation__(*coerced_args, **coerced_kwargs)
Actually, this might in fact work with the plan proposed here, if we allow for an extra, optional kwarg that contains the coercion function, that is
    return function.__implementation__(*args, coercion_function=np.asanyarray, **kwargs)

The possible advantage of this over yet more dunder methods is that one can fine-tune the extent to which something has to mimic an array properly (e.g., run `asanyarray` only if `shape` is not present).

It would be nice, though, if we could end up with also option 4 being available, if only because code that just can assume ndarray will be easiest to read.

All the best,

NumPy-Discussion mailing list

Hi everyone,

Although, in general, I agree with Stephan’s design goals, I agree with Marten that the number of protocols are getting larger and may get out of hand if not handled properly. There’s even one Marten forgot to mention: __array_dtype__. I have been working on a project that I consider to have all the essential features that Marten proposes, mostly within one framework. It’s called uarray (for universal array) and can be found over at 

It adopts the “separation of implementation from interface” principles from the beginning. Here’s how it works: There are MultiMethods and Backends. A Backend registers implementations for a given MultiMethod. A MultiMethod defines the signature, along with the elements that can be dispatched over, along with their types. To it, NumPy is (and I realise this is going to be controversial, since this is the NumPy mailing list), just another backend.

Here’s how it addresses Marten’s concerns:
  • Everything is made into a MultiMethod. Then, the multimethod marks objects it’d like to dispatch over. For the status quo, this is arrays. But thinking long-term, we could dispatch over abstract ufuncs and dtypes as well. For ufuncs, ufunc.__call__ and ufunc.reduce are also MultiMethods.
  • Coercion works by extracting marked dispatchables, converting them into native library equivalents and then passing them back into the function. For example, it would convert lists (or anything marked as an array) to arrays. What it could also do is convert dtype=‘int64’ to an actual dtype, and so on.
  • __asduckarray__ is rendered unnecessary… Coercion handles that.
You can check out the usage examples in the tests:

Examples of how to write NumPy MultiMethods are here: https://github.com/Quansight-Labs/uarray/blob/master/unumpy/multimethods.py, along with the accompanying Backends in https://github.com/Quansight-Labs/uarray/tree/master/unumpy.

Best Regards,
Hameer Abbasi