<div dir="ltr"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div>I don't think so. Dtypes have nothing to do with a whole set of use
 cases that add extra methods or attributes. Random made-up example: 
user has a system with 1000 sensor signals, some of which should be 
treated with robust statistics for <reasons like unreliable 
hardware>. So user writes a subclass robust_ndarray, adds a bunch of 
methods like median/iqr/mad, and uses isinstance checks in functions 
that accept both ndarray and robust_ndarray to figure out how to 
preprocess sensor signals. <br></div><div><br></div><div>Of course you 
can do everything you can do with subclasses also in other ways, but 
such "let's add some methods or attributes" are much more common (I 
think, hard to prove) than "let's change how indexing or multiplication 
works" in end user code.</div><div><br></div><div>Cheers,<br></div><div>Ralf</div></blockquote><div><br></div><div>The build on Ralf's thought, a common subclass use case would be to add logging to various methods and attributes.  That might actually be useful for ndarray for understanding what is under the hood of some function in a downstream project.  It would satisfy SOLID and not be related at all to dtype subclasses.<br></div><div> <br></div></div><br><div class="gmail_quote"><div dir="ltr">On Wed, Oct 31, 2018 at 8:28 PM Ralf Gommers <<a href="mailto:ralf.gommers@gmail.com">ralf.gommers@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"><br><br><div class="gmail_quote"><div dir="ltr">On Tue, Oct 30, 2018 at 2:22 PM Stephan Hoyer <<a href="mailto:shoyer@gmail.com" target="_blank">shoyer@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 class="gmail_quote"><div dir="ltr">On Mon, Oct 29, 2018 at 9:49 PM Eric Wieser <<a href="mailto:wieser.eric%2Bnumpy@gmail.com" target="_blank">wieser.eric+numpy@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 class="m_-4997309944532999056m_-1726338779398554096m_-1612426709946026299markdown-here-wrapper" style="font-size:1em;font-family:Helvetica,arial,freesans,clean,sans-serif;color:rgb(34,34,34);background-color:rgb(255,255,255);border:none;line-height:1.2"><blockquote style="margin:1em 0px;border-left:4px solid rgb(221,221,221);padding:0px 1em;color:rgb(119,119,119);quotes:none">
<p style="margin:1em 0px">The latter - changing the behavior of multiplication breaks the principle.</p>
</blockquote>
</div></div><div dir="ltr"><div class="m_-4997309944532999056m_-1726338779398554096m_-1612426709946026299markdown-here-wrapper" style="font-size:1em;font-family:Helvetica,arial,freesans,clean,sans-serif;color:rgb(34,34,34);background-color:rgb(255,255,255);border:none;line-height:1.2"><p style="margin:1em 0px">But this is not the main reason for deprecating matrix - almost all of the problems I’ve seen have been caused by the way that matrices behave when sliced. The way that <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">m[i][j]</code> and <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">m[i,j]</code> are different is just one example of this, the fact that they must be 2d is another.</p>
<p style="margin:1em 0px">Matrices behaving differently on multiplication isn’t super different in my mind to how string arrays fail to multiply at all.</p></div></div><div dir="ltr"><div class="m_-4997309944532999056m_-1726338779398554096m_-1612426709946026299markdown-here-wrapper" style="font-size:1em;font-family:Helvetica,arial,freesans,clean,sans-serif;color:rgb(34,34,34);background-color:rgb(255,255,255);border:none;line-height:1.2">
<p style="margin:1em 0px">Eri<span style="font-size:1em">c</span></p></div></div></blockquote><div>It's certainly fine for arithmetic to work differently on an element-wise basis or even to error. But np.matrix changes the shape of results from various ndarray operations (e.g., both multiplication and indexing), which is more than any dtype can do.<br></div><div><br></div><div>The Liskov substitution principle (LSP) suggests that the set of reasonable ndarray subclasses are exactly those that could also in principle correspond to a new dtype. </div></div></div></blockquote><div><br></div><div>I don't think so. Dtypes have nothing to do with a whole set of use cases that add extra methods or attributes. Random made-up example: user has a system with 1000 sensor signals, some of which should be treated with robust statistics for <reasons like unreliable hardware>. So user writes a subclass robust_ndarray, adds a bunch of methods like median/iqr/mad, and uses isinstance checks in functions that accept both ndarray and robust_ndarray to figure out how to preprocess sensor signals. <br></div><div><br></div><div>Of course you can do everything you can do with subclasses also in other ways, but such "let's add some methods or attributes" are much more common (I think, hard to prove) than "let's change how indexing or multiplication works" in end user code.</div><div><br></div><div>Cheers,<br></div><div>Ralf</div><div><br></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 class="gmail_quote"><div>Of np.ndarray subclasses in wide-spread use, I think only the various "array with units" types come close satisfying this criteria. They only fall short insofar as they present a misleading dtype (without unit information).</div><div><br></div><div>The main problem with subclassing for numpy.ndarray is that it guarantees too much: a large set of operations/methods along with a specific memory layout exposed as part of its public API. Worse, ndarray itself is a little quirky (e.g., with indexing, and its handling of scalars vs. 0d arrays). In practice, it's basically impossible to layer on complex behavior with these exact semantics, so only extremely minimal ndarray subclasses don't violate LSP.</div><div><br></div><div>Once we have more easily extended dtypes, I suspect most of the good use cases for subclassing will have gone away.</div></div></div>
_______________________________________________<br>
NumPy-Discussion mailing list<br>
<a href="mailto:NumPy-Discussion@python.org" target="_blank">NumPy-Discussion@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/numpy-discussion" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/numpy-discussion</a><br>
</blockquote></div></div>
_______________________________________________<br>
NumPy-Discussion mailing list<br>
<a href="mailto:NumPy-Discussion@python.org" target="_blank">NumPy-Discussion@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/numpy-discussion" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/numpy-discussion</a><br>
</blockquote></div>