Hi Nathaniel, Thanks, I now see your point. I think I can weasel my way partially out: the default *output* from `np.concatenate` is an ndarray, so in that respect it is not that strange that when no input defines __array_function__, one would call `ndarray.__array_function__` (I realize this is sophistry and that it breaks down with all-scalar functions, but still feel it is defensible...). Your point about `__skipping_array_function__` is well taken, though: it is not very logical since suddenly one again ignores items that define __array_function__. Its real purpose is to be a useful crutch if one wants to start to define __array_function__ on one's class. But arguably this is yet more reason to just stick with __wrapped__ - i.e., be explicit that it is an implementation detail. All the best, Marten On Sun, Apr 28, 2019 at 6:50 PM Nathaniel Smith <njs@pobox.com> wrote:
On Sun, Apr 28, 2019 at 1:38 PM Marten van Kerkwijk <m.h.vankerkwijk@gmail.com> wrote:
Hi Nathaniel,
I'm a bit confused why` np.concatenate([1, 2], [3, 4])` would be a
problem. In the current model, all (numpy) functions fall back to `ndarray.__array_function__`, which does know what to do with anything that doesn't have `__array_function__`: it just coerces it to array. Am I missing something?
IMO, the reason that having ndarray.__array_function__ was attractive in the first place, was that we were hoping it would let you pretend that there's nothing special about ndarray. Like, when you call np.concatenate, it just looks for __array_function__ methods and dispatches to them; sometimes that means calling thirdpartyobject.__array_function__, and sometimes it means calling ndarray.__array_function__, but as far as np.concatenate is concerned those are interchangeable and treated in the same way.
But in fact ndarray.__array_function__ *is* special. I guess you could write down the semantics so that np.concatenate([1, 2], [3, 4]) still calls ndarray.__array_function__, by defining a special dispatch rules just for ndarray.__array_function__. But if ndarray.__array_function__ isn't going to follow the same dispatch rule, then why should it exist and be called "__array_function__"? A special method like "__array_function__" is nothing except a name for a dispatch rule.
And if we add __skipping_array_function__, it makes this even worse. In a model where dispatch always goes through *some* object's __array_function__, then __skipping_array_function__ makes no sense -- if you skip __array_function__ then there's nothing left.
You might try to save it by saying, ok, we'll only skip third-party __array_function__, but still dispatch to ndarray.__array_function__. But this doesn't work either. np.concatenate.__skipping_array_function__(...) is different from ndarray.__array_function__(np.concatenate, ...), because they treat arguments with __array_function__ methods differently. (The former coerces them to ndarray; the latter returns NotImplemented.) Neither can be implemented in terms of the other (!).
ndarray.__array_function__ was a nice idea, but I don't think there's any way to fit into a coherent system.
-n
-- Nathaniel J. Smith -- https://vorpus.org _______________________________________________ NumPy-Discussion mailing list NumPy-Discussion@python.org https://mail.python.org/mailman/listinfo/numpy-discussion