<div dir="ltr"><div class="gmail_quote"><div dir="ltr">On Sun, Jun 3, 2018 at 8:19 AM Marten van Kerkwijk <<a href="mailto:m.h.vankerkwijk@gmail.com">m.h.vankerkwijk@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><div>My more general comment is one of speed: for *normal* operation performance should
 be impacted as minimally as possible. I think this is a serious issue and feel strongly it *has* to be possible to avoid all arguments being checked for the `__array_function__` attribute, i.e., there should be an obvious way to 
ensure no type checking dance is done.</div></div></div></blockquote><div><br></div><div>I agree that all we should try minimize the impact of dispatching on normal operations. It would be helpful to identify examples of real workflows, so we can measure the impact of doing these checks empirically. That said, I think a small degradation in performance for code that works with small arrays should be acceptable, because performance is an already an accepted limitations of using NumPy/Python for these use cases.</div><div><br></div><div>In most cases, I suspect that the overhead of a function call and checking several arguments for "__array_function__" will be negligible, like the situation for __array_ufunc__. I'm not strongly opposed to either of your proposed solutions, but I do think it would be a little strange to insist that we need a solution for __array_function__ when __array_ufunc__ was fine.</div><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><div>A. Two 
"namespaces", one for the undecorated base functions, and one completely trivial one for the 
decorated ones. The idea would be that if one knows one is dealing with 
arrays only, one would do `import numpy.array_only as np` (i.e., the reverse of the suggestion currently in the NEP, where the decorated ones are in their own namespace - I agree with the reasons for discounting that one).<br></div></div></div></blockquote><div><br></div><div>I will mention this as a possibility.</div><div><br></div><div>I do think there is something to be said for clear separation of overloaded and non-overloaded APIs. But f I were to choose between adding numpy.api and numpy.array_only, I would pick numpy.api, because of the virtue of preserving the existing numpy namespace as it currently exists.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><span style="color:rgb(33,33,33);font-size:13px">B. Automatic insertion by the decorator of an `array_only=np._NoValue` (or `coerce` and perhaps `subok=...` if not present) in the function signature, so that users who know that they have arrays only could pass `array_only=True` (name to be decided).</span></div></div></blockquote><div><br></div><div>Rather than adding another argument to every NumPy function, I would rather encourage writing np.asarray() explicitly.</div><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div>Note that both A and B could also address, at least partially, the problem of sometimes wanting to just use the old coercion methods, i.e., not having to implement every possible numpy function in one go in a new `__array_function__` on one's class.</div></div></blockquote><div><br></div><div>Yes, agreed. </div><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div></div><div>1. I'm rather unclear about the use of `types`. It can help me decide what to do, but I would still have to find the argument in question (e.g., for Quantity, the unit of the relevant argument). I'd recommend passing instead a tuple of all arguments that were inspected, in the inspection order; after all, it is just a `arg.__class__` away from the type, and in your example you'd only have to replace `issubclass` by `isinstance`.<br></div></div></blockquote><div><br></div><div>The virtue of a `types` argument is that we can deduplicate arguments once, rather than in each __array_function__ check. This could result in significantly more efficient code, e.g,. when np.concatenate() is called on 10,000 arrays with only two unique types, we don't need to loop through all 10,000 again objects to check that overloading is valid.<br></div><div><br></div><div>Even for Quantity, I suspect you will want two layers of checks:</div><div>1. A check to verify that every argument is a Quantity (or something coercible to a Quantity). This could use `types` and return `NotImplemented` when it fails.</div><div>2. A check to verify that units match. This will have custom logic for different operations and will require checking all arguments -- not just their unique types.</div><div><br></div><div>For many Quantity functions, the second check will indeed probably be super simple (i.e., verifying that all units match). But the first check (with `types`) really is something that basically very overload should do.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div></div><div>2. For subclasses, it would be very handy to have `ndarray.__array_function__`, so one can call super after changing arguments. (For `__array_ufunc__`, there was lots of question about whether this was useful, but it really is!!). [I think you already agreed with this, but want to have it in-place, as for subclasses of ndarray this is just as useful as it would be for subclasses of dask arrays.)<br></div></div></blockquote><div><br></div><div>Yes, indeed.</div></div></div>