opIndex() may hide opSlice()

H. S. Teoh via Digitalmars-d digitalmars-d at puremagic.com
Fri Mar 10 14:07:59 PST 2017


On Fri, Mar 10, 2017 at 12:36:35PM -0800, Jonathan M Davis via Digitalmars-d wrote:
> On Friday, March 10, 2017 10:43:43 H. S. Teoh via Digitalmars-d wrote:
[...]
> Well, thanks for the explanation, but I'm sure that part of the
> problem here is that an operation like arr[x, y..z] doesn't even make
> sense to me. I have no idea what that does.

That's a subdimensional slice. In this case, we're dealing with a 2D
array -- you can think of it as a matrix -- and extracting the y'th to
z'th elements from column x.  Conversely, arr[x..y, z] extracts the x'th
to y'th elements from row z.  This kind of subdimensional slicing is
pretty common when you work with things like tensors.


> But I don't normally do anything with multidimensional arrays, and in
> the rare case that I do, I certainly don't need to overload anything
> for them. I just slap together a multidimensional array of whatever
> type it is I want in a multidimensional array.

If by "multidimensional arrays" you mean arrays of arrays, then I can
understand your sentiment.

But when dealing with high-dimensional tensors, storing them explicitly
may not always be the best approach. Think sparse matrices, for example.
You want to be able to provide array indexing / slicing operations to
user types apart from the built-in arrays.

Not to mention that there are many problems with using arrays of arrays
as "multidimensional" arrays, besides storage issues. One being that you
can't easily represent a slice of an array of arrays across the minor
dimension (i.e., a slice of every i'th element of each array in an
int[][]).  For things like that, you *really* want to be able to write
arr[x, y..z] and arr[x..y, z] rather than arr[x][y..z] and arr[x..y][z].
Doing it the latter way means you need to implement arr.opSlice that
returns a proxy type that implements opIndex.  Kenji's design allows you
to implement all of these cases (and more) by just implementing a single
type with a single opSlice and single opIndex, and no proxy types, to
boot. It's clean and elegant.


> I can certainly understand that there are folks who really do care
> about this stuff, but it's completely outside of what I deal with, and
> for anything I've ever dealt with, making opIndex be for _slicing_
> makes no sense whatsoever, and the added functionality to the language
> with regards to multi-dimensional arrays is useless. So, this whole
> mess has always felt like I've had something nonsensical thrown at me
> because of a use case that I don't even properly understand.

Please don't denigrate something as useless without at least trying to
understand it first.


[...]
> Well, I'd prefer that the original way be left, since that's all I've
> ever needed. If the new way makes life easier for the scientific
> programmers and whatnot, then great, but from the standpoint of anyone
> not trying to provide multi-dimensional overloads, using opIndex for
> slicing is just plain bizarre.

Actually, it's the distinction between opSlice and opIndex in the old
scheme that's what's bizarre. It's like saying that to implement
userType(x) you need to declare userType.opSingleArgCall and to
implement userType(x,y) you need to declare userType.opTwoArgCall, just
because there happens to be 2 arguments instead of 1.  Why not just
unify the two under a single opCall, just with two overloads depending
on what arguments you want to pass to it?

In the same vein, requiring two different methods to implement arr[x]
vs. arr[x..y] is bizarre.  They should be unified under a single method
-- I don't care what you call it, maybe opIndex is a bad name because it
gives the wrong connotation for what it does, maybe it should be named
opSquareBrackets or something. But the point is that this distinction
between how arr[x] and arr[x..y] are handled is artificial and needless,
and does not easily generalize to higher dimensions.  Kenji's design is
far superior.


> That being said, I'm fine with the compiler detecting if opIndex and
> opSlice are declared in a way that they conflict and then giving an
> error. I just don't want to be forced to use opIndex for slicing.
[...]

Nobody is forcing you to use opIndex for slicing right now, because the
compiler currently accepts the old syntax for 1-dimensional arrays. And
I already said it's probably a bad idea to deprecate the old syntax.


T

-- 
What do you mean the Internet isn't filled with subliminal messages? What about all those buttons marked "submit"??


More information about the Digitalmars-d mailing list