<div dir="ltr"><div dir="ltr">On Wed, Apr 24, 2019 at 9:56 PM Nathaniel Smith <<a href="mailto:njs@pobox.com">njs@pobox.com</a>> wrote:<br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">When you say "numpy array specific" and<br>
"__numpy_(nd)array_implementation__", that sounds to me like you're<br>
trying to say "just step 3, skipping steps 1 and 2"? Step 3 is the one<br>
that operates on ndarrays...<br></blockquote><div><br></div><div>My thinking was that if we implement NumPy functions with duck typing (e.g., `np.stack()` in terms of  `.shape` + `np.concatenate()`), then step (3) could in some sense be the generic "array implementation", not only for NumPy arrays.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
When we have some kind of __asduckarray__ coercion, then that will<br>
complicate things too, because presumably we'll do something like<br>
<br>
1. __array_function__ dispatch<br>
2. __asduckarray__ coercion<br>
3. __array_function__ dispatch again<br>
4. ndarray coercion<br>
5. [either "the implementation", or __array_function__ dispatch again,<br>
depending on how you want to think about it]<br></blockquote><div><br></div><div>I was thinking of something a little simpler: do __asduckarray__ rather than numpy.ndarray coercion inside the implementation of NumPy functions. Then making use of NumPy's implementations would be a matter of calling the NumPy implementation without ndarray coercion from side __array_function__.</div><div><br></div><div>e.g.,</div><div><br></div><div>class MyArray:</div><div>    def __duck_array__(self):</div><div>        return self</div><div>    def __array_function__(self, func, types, args, kwargs):</div><div>        ...</div><div>        if func in {np.stack, np.atleast_1d, ...}:</div><div>            # use NumPy's "duck typing" implementations for these functions</div><div>            return func.__duck_array_implementation__(*args, **kwargs)</div><div>        elif func == np.concatenate:</div><div>            # write my own version of np.concatenate</div><div>            ...</div><div><br></div><div>This would let you make use of duck typing in a controlled way if you use __array_function__. np.stack.__duck_array_implementation__ would look exactly like np.stack, except np.asanyarray() would be replaced by np.asduckarray().</div><div><br></div><div>The reason why we need the separate __duck_array_implementation__ and __numpy_array_implementation__/__skipping_array_function__ is because there are also use cases where you *don't* want to worry about how np.stack is implemented under the hood (i.e., in terms of np.concatenate), and want to go straight to the coercive numpy.ndarray implementation. This lets you avoid both the complexity and overhead associated with further dispatch checks.</div><div><br></div><div>I don't think we want repeated dispatching with __array_function__. That seems like a recipe for slow performance and confusion.</div></div></div>