www.digitalmars.com         C & C++   DMDScript  

D - Array operator overloading

reply "Walter" <walter digitalmars.com> writes:
I'm thinking that the following operator overload functions will cover the
territory. Have I missed anything?

x = foo[y];    =>   x = foo.opIndex(y);

foo[y] = x;    =>   foo.opIndexAss(y, x);

foo[a .. b]     =>   foo.opSlice(a, b);

And yes, I think the other operator overloads should be renamed with an "op"
prefix.
Sep 08 2003
next sibling parent reply "QUS" <qus go2.pl> writes:
 x = foo[y];    =>   x = foo.opIndex(y);

 foo[y] = x;    =>   foo.opIndexAss(y, x);

 foo[a .. b]     =>   foo.opSlice(a, b);

 And yes, I think the other operator overloads should be renamed with an

 prefix.

operatorIndex operatorAdd operatorMulass etc?
Sep 08 2003
parent reply Helmut Leitner <leitner hls.via.at> writes:
QUS wrote:
 
 x = foo[y];    =>   x = foo.opIndex(y);

 foo[y] = x;    =>   foo.opIndexAss(y, x);

 foo[a .. b]     =>   foo.opSlice(a, b);

 And yes, I think the other operator overloads should be renamed with an

 prefix.

operatorIndex operatorAdd operatorMulass

"Add" seems wrong to me, because no element is added in the usual sense. "Mulass" seems wrong to me, because it is not a "multiple assignment", but a single assignment of an array part to an array reference. In my language built with reusable "words": opIndRetElement opIndSetElement opIndRangeRetSlice (but I would not expect it to be adopted) -- Helmut Leitner leitner hls.via.at Graz, Austria www.hls-software.com
Sep 08 2003
parent "QUS" <qus go2.pl> writes:
"Helmut Leitner" <leitner hls.via.at> wrote in message
news:3F5C45DE.3AC22592 hls.via.at...
 QUS wrote:
 x = foo[y];    =>   x = foo.opIndex(y);

 foo[y] = x;    =>   foo.opIndexAss(y, x);

 foo[a .. b]     =>   foo.opSlice(a, b);

 And yes, I think the other operator overloads should be renamed with



 "op"
 prefix.

operatorIndex operatorAdd operatorMulass

"Add" seems wrong to me, because no element is added in the usual sense. "Mulass" seems wrong to me, because it is not a "multiple assignment", but a single assignment of an array part to an array reference. In my language built with reusable "words": opIndRetElement opIndSetElement opIndRangeRetSlice

had nothing to do with array overloading :-)
Sep 08 2003
prev sibling next sibling parent "Matthew Wilson" <matthew stlsoft.org> writes:
Well, I'm not fond of having my ass indexed!

I think a prefix of op is not good enough (i.e. not sufficiently unique).

I would prefer

  OP_slice, or op_slice

As for the two index operators, I think they should be called

  op_index_r and op_index_l (for rvalue and lvalue)

But actually I think this may not be the whole solution. We might want to
return a proxy object for both types, as one does in C++. In that case, we'd
want

  op_index_l
  op_index_r
  op_index

op_index would only be called where one or other of the l/r variants was not
provided.



"Walter" <walter digitalmars.com> wrote in message
news:bjhefn$2qdb$1 digitaldaemon.com...
 I'm thinking that the following operator overload functions will cover the
 territory. Have I missed anything?

 x = foo[y];    =>   x = foo.opIndex(y);

 foo[y] = x;    =>   foo.opIndexAss(y, x);

 foo[a .. b]     =>   foo.opSlice(a, b);

 And yes, I think the other operator overloads should be renamed with an

 prefix.

Sep 08 2003
prev sibling next sibling parent "Riccardo De Agostini" <riccardo.de.agostini email.it> writes:
"Walter" <walter digitalmars.com> ha scritto nel messaggio
news:bjhefn$2qdb$1 digitaldaemon.com...
 foo[y] = x;    =>   foo.opIndexAss(y, x);

Maybe opIndexAsLValue, although maybe too verbose, is a better choice. At least it leaves both hands free for typing. ;-) BTW, I find "op" as a prefix a little too concise; I'd vote for "operator", or "op_" as suggested by Matthew. Ric
Sep 08 2003
prev sibling next sibling parent "Sean L. Palmer" <palmer.sean verizon.net> writes:
"Walter" <walter digitalmars.com> wrote in message
news:bjhefn$2qdb$1 digitaldaemon.com...
 I'm thinking that the following operator overload functions will cover the
 territory. Have I missed anything?

 x = foo[y];    =>   x = foo.opIndex(y);

 foo[y] = x;    =>   foo.opIndexAss(y, x);

 foo[a .. b]     =>   foo.opSlice(a, b);

 And yes, I think the other operator overloads should be renamed with an

 prefix.

I'm ok with the short op prefix as you suggest. I do not see how one could pull off multidimensional arrays without proxy objects. I think we should be able to declare indexing functions that take more than one argument, and the compiler would give us syntax sugar like so: template (T : numeric, int cols, int rows) struct matrix { private T array[rows][cols]; public T opIndex(int col, int row) { return array[row][col]; } public void opIndexSet(T val, int col, int row) { array[row][col] = val; } public instance matrix(T, colrange.end-colrange.begin, rowrange.end-rowrange.begin).matrix opSlice(range(int) colrange, range(int) rowrange) { return array[rowrange.begin..rowrange.end][colrange.begin..colrange.end]; } } instance matrix(float, 4, 4).matrix mymatrix; mymatrix[3][2] = 1.0f; // calls opIndexSet(1.0f,2,3) float x = mymatrix[3][2]; // calls opIndex(2,3) instance matrix(float, 2, 2).matrix submatrix = matrix[1..3][0..2]; // calls opSlice(0..2,1..3) And one more thing... we need to be able to override the array .length property. Hopefully you can override a predefined property with a user-defined one. Sean
Sep 08 2003
prev sibling next sibling parent Ilya Minkov <minkov cs.tum.edu> writes:
Walter wrote:
 I'm thinking that the following operator overload functions will cover the
 territory. Have I missed anything?

Seems to be all there. But you have to know it better. :) Ah, yes, the multi-dimensional ones would be good, since you provide different names anyway this shouldn't be a problem, right?
 x = foo[y];    =>   x = foo.opIndex(y);
 
 foo[y] = x;    =>   foo.opIndexAss(y, x);

x = foo[y,z]; => x = foo.opIndex(y,z); foo[y,z] = x; => foo.opIndexAss(y,z,x);
 foo[a .. b]     =>   foo.opSlice(a, b);

foo[a,b .. c,d] => foo.opSlice(a,b,c,d); Could this possibly work at all??? Is it supposed to return a new array or a proxy object at will?
 And yes, I think the other operator overloads should be renamed with an "op"
 prefix.

Seems to be a good idea to me... But what about that _r postfix? You get opDiv_r -- which seems to be inconsistent within itself? How about op_div_r, and so on for operator naming? Or do you prefer opDivR? Is there any chance to keep naming for array access consistent with properties? In Delphi, an object can contain a number of array acessors which would work like properties. Then you can pick up one of them and set a default attribute for it, then acessing an object as an array would use exactly these acessors... In D this may better simply be the name of the array property. -eye
Sep 08 2003
prev sibling next sibling parent reply "Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> writes:
"Walter" <walter digitalmars.com> escreveu na mensagem
news:bjhefn$2qdb$1 digitaldaemon.com...
 I'm thinking that the following operator overload functions will cover the
 territory. Have I missed anything?

 x = foo[y];    =>   x = foo.opIndex(y);

 foo[y] = x;    =>   foo.opIndexAss(y, x);

 foo[a .. b]     =>   foo.opSlice(a, b);

 And yes, I think the other operator overloads should be renamed with an

 prefix.

Why not: x = foo[y]; => x = foo.get(y); foo[y] = x; => foo.set(y, x); foo[a .. b] => foo.slice(a, b); The other operator names are already nice (i.e. "add" instead of "opAdd"). BTW will array operations be overloaded? Today the spec says: a[] = b[] + 3; => for (int i = 0; i < a.length; i++) { a[i] = b[i] + 3; } But if I have a collection, will it work? I'm saying that because we'll need to define some array-like data-structures (e.g. matrices, vector spaces) and would be nice to have array operations (like Blitz++ has tensor notation). Perhaps an "indices" operation could be used: a[] = b[] + 3; foreach (??? i; a.indices()) {a[i] = b[i] + 3; } Also it would be nice if I could define more than one index, so a matrix could be written: x = foo[i, j]; => x = foo.get(i, j); foo[i, j] = x; => foo.set(i, j, x); foo[0 .. a, 0 .. b] => foo.slice(0 .. a, 0 .. b); Best regards, Daniel Yokomiso. "Sometimes I think the surest sign that intelligent life exists elsewhere in the universe is that none of it has tried to contact us." - Bill Watterson --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.514 / Virus Database: 312 - Release Date: 28/8/2003
Sep 08 2003
parent reply "Walter" <walter digitalmars.com> writes:
"Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> wrote in message
news:bjj5bg$2ah0$1 digitaldaemon.com...
 "Walter" <walter digitalmars.com> escreveu na mensagem
 news:bjhefn$2qdb$1 digitaldaemon.com...
 I'm thinking that the following operator overload functions will cover


 territory. Have I missed anything?

 x = foo[y];    =>   x = foo.opIndex(y);

 foo[y] = x;    =>   foo.opIndexAss(y, x);

 foo[a .. b]     =>   foo.opSlice(a, b);

 And yes, I think the other operator overloads should be renamed with an

 prefix.

x = foo[y]; => x = foo.get(y); foo[y] = x; => foo.set(y, x); foo[a .. b] => foo.slice(a, b); The other operator names are already nice (i.e. "add" instead of "opAdd"). BTW will array operations be overloaded? Today the spec says:

Hmm. I kinda was thinking "add" was just a little too generic, that it might need something to say it's a magic function to the compiler. Python sets off the operator overloading with a __ prefix and postfix (which I find unattractive, but it does stand out).
 a[] = b[] + 3;    =>  for (int i = 0; i < a.length; i++) { a[i] = b[i] +
 3; }
 But if I have a collection, will it work? I'm saying that because we'll

 to define some array-like data-structures (e.g. matrices, vector spaces)

 would be nice to have array operations (like Blitz++ has tensor notation).
 Perhaps an "indices" operation could be used:


 a[] = b[] + 3;

 foreach (??? i; a.indices()) {a[i] = b[i] + 3; }

Since [] is a slice operation, I was thinking that this could be handled with the slice operator overload (having it return a different object, with its own operator overloads).
 Also it would be nice if I could define more than one index, so a matrix
 could be written:


 x = foo[i, j];        =>   x = foo.get(i, j);

 foo[i, j] = x;        =>   foo.set(i, j, x);

 foo[0 .. a, 0 .. b]   =>   foo.slice(0 .. a, 0 .. b);

Sean has some ideas along this line: x = foo[x][y]; => x = foo.get(x,y);
Sep 08 2003
next sibling parent reply "Matthew Wilson" <matthew stlsoft.org> writes:
Sean's ideas sound quite good. I'm not sure I saw different _l and _r in
there, though.

One thing I *definitely* think is important, is to avoid generic names such
as add(). At minimum it should be op_add(), and I'd prefer __add__(), or
even __op_add__().


"Walter" <walter digitalmars.com> wrote in message
news:bjjd6g$2kvk$1 digitaldaemon.com...
 "Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> wrote in message
 news:bjj5bg$2ah0$1 digitaldaemon.com...
 "Walter" <walter digitalmars.com> escreveu na mensagem
 news:bjhefn$2qdb$1 digitaldaemon.com...
 I'm thinking that the following operator overload functions will cover


 territory. Have I missed anything?

 x = foo[y];    =>   x = foo.opIndex(y);

 foo[y] = x;    =>   foo.opIndexAss(y, x);

 foo[a .. b]     =>   foo.opSlice(a, b);

 And yes, I think the other operator overloads should be renamed with



 "op"
 prefix.

x = foo[y]; => x = foo.get(y); foo[y] = x; => foo.set(y, x); foo[a .. b] => foo.slice(a, b); The other operator names are already nice (i.e. "add" instead of


 BTW will array operations be overloaded? Today the spec says:

Hmm. I kinda was thinking "add" was just a little too generic, that it

 need something to say it's a magic function to the compiler. Python sets

 the operator overloading with a __ prefix and postfix (which I find
 unattractive, but it does stand out).

 a[] = b[] + 3;    =>  for (int i = 0; i < a.length; i++) { a[i] = b[i] +
 3; }
 But if I have a collection, will it work? I'm saying that because we'll

 to define some array-like data-structures (e.g. matrices, vector spaces)

 would be nice to have array operations (like Blitz++ has tensor


 Perhaps an "indices" operation could be used:


 a[] = b[] + 3;

 foreach (??? i; a.indices()) {a[i] = b[i] + 3; }

Since [] is a slice operation, I was thinking that this could be handled with the slice operator overload (having it return a different object,

 its own operator overloads).

 Also it would be nice if I could define more than one index, so a matrix
 could be written:


 x = foo[i, j];        =>   x = foo.get(i, j);

 foo[i, j] = x;        =>   foo.set(i, j, x);

 foo[0 .. a, 0 .. b]   =>   foo.slice(0 .. a, 0 .. b);

Sean has some ideas along this line: x = foo[x][y]; => x = foo.get(x,y);

Sep 09 2003
parent reply "Sean L. Palmer" <palmer.sean verizon.net> writes:
"Matthew Wilson" <matthew stlsoft.org> wrote in message
news:bjk32t$l31$1 digitaldaemon.com...
 Sean's ideas sound quite good. I'm not sure I saw different _l and _r in
 there, though.

You could certainly have a different one for get than for set. It might be nice to support [x,y] notation as well, especially for true rectangular arrays, not arrays of arrays. But that would conflict with the comma operator. There are already conflicts with the comma operator pretty much everywhere comma is accepted (i.e. parameter lists) so this is not the end of the world.
 One thing I *definitely* think is important, is to avoid generic names

 as add(). At minimum it should be op_add(), and I'd prefer __add__(), or
 even __op_add__().

I prefer the "real" names: operator + operator [] etc. There is no possibility of confusion, and you're saying exactly what you want. You want an operator overload for +=, then by god overload operator +=, not "addass". This would leave *all* those names available for the user member namespace. Sean
Sep 09 2003
next sibling parent reply Mike Wynn <mike l8night.co.uk> writes:
Sean L. Palmer wrote:
 "Matthew Wilson" <matthew stlsoft.org> wrote in message
 news:bjk32t$l31$1 digitaldaemon.com...
 
Sean's ideas sound quite good. I'm not sure I saw different _l and _r in
there, though.

You could certainly have a different one for get than for set. It might be nice to support [x,y] notation as well, especially for true rectangular arrays, not arrays of arrays. But that would conflict with the comma operator. There are already conflicts with the comma operator pretty much everywhere comma is accepted (i.e. parameter lists) so this is not the end of the world.

yes, dump the comma operator, for those that want it add "eval" if you realy need a set of expressions as an expression. x = eval( a = x, b=c, c ); same as current `x = (a=x), (b=c), c; ` then comma is just list separator in all cases. eval is kind of extern(pascal order, caller clean up) T eval( ..., T rv );
Sep 09 2003
parent Ilya Minkov <webmaster midiclub.de.vu> writes:
Mike Wynn wrote:

 yes, dump the comma operator, for those that want it add "eval" if you 
 realy need a set of expressions as an expression.
 x = eval( a = x, b=c, c ); same as current `x = (a=x), (b=c), c; `
 then comma is just list separator in all cases.
 eval is kind of
 extern(pascal order, caller clean up) T eval( ..., T rv );

With a recursive descend parser it shouldn't matter that something conflicts with a comma operator, as long as you don't need to expect comma operator in the same context. However, i think dunping the operator and providing a named variant for it is a good idea! However, as it cannot be overloaded, i can hardly figure out any use for it at all... -eye
Sep 09 2003
prev sibling next sibling parent reply "Matthew Wilson" <matthew stlsoft.org> writes:
 One thing I *definitely* think is important, is to avoid generic names

 as add(). At minimum it should be op_add(), and I'd prefer __add__(), or
 even __op_add__().

I prefer the "real" names: operator + operator [] etc. There is no possibility of confusion, and you're saying exactly what you want. You want an operator overload for +=, then by god overload operator +=, not "addass".

Even better!
Sep 09 2003
parent reply "Philippe Mori" <philippe_mori hotmail.com> writes:
"Matthew Wilson" <matthew stlsoft.org> a écrit dans le message de
news:bjldl8$2j4j$1 digitaldaemon.com...
 One thing I *definitely* think is important, is to avoid generic names

 as add(). At minimum it should be op_add(), and I'd prefer __add__(),



 even __op_add__().

I prefer the "real" names: operator + operator [] etc. There is no possibility of confusion, and you're saying exactly what you want. You want an operator overload for +=, then by god overload


 +=, not "addass".

Even better!

I also prefer "real" name... as in C++ but I think that for postfix++ and similar it should be a "postfix" modifier... and for case where we want to make the distinction between l-value and r-value, we should also uses a modifier. I would like that operator[] support multiple arguments as a function and yes we might uses the suggestion eval for an expression that presently uses comman operator and ban it. but if something like eval is added, I would also like that this would be possible: if (int a = f(), a == 25) { } where we could do 1 (ore more) declaration and expression before doing the test... we might uses eval and/or some other keyword presently, in C++ the trick to declare the variable inside an expression essentially only works when we test against 0...
Sep 09 2003
parent "Sean L. Palmer" <palmer.sean verizon.net> writes:
-operator
+operator
++operator
--operator
operator++
operator--
oper+ator
oper-ator
oper*ator
oper/ator
oper,ator    // I don't mind operator comma as long as you use it to build a
list or sequence
operator[]
operator[][]

Harharhar!

Sean

"Philippe Mori" <philippe_mori hotmail.com> wrote in message
news:bjlhf8$2oi4$1 digitaldaemon.com...
 I also prefer "real" name... as in C++ but I think that for postfix++ and
 similar it should be a "postfix" modifier... and for case where we want
 to make the distinction between l-value and r-value, we should also
 uses a modifier.

 I would like that operator[] support multiple arguments as a function
 and yes we might uses the suggestion eval for an expression
 that presently uses comman operator and ban it.

 but if something like eval is added, I would also like that
 this would be possible:

 if (int a = f(), a == 25)
 {
 }

 where we could do 1 (ore more) declaration and expression before
 doing the test... we might uses eval and/or some other keyword

 presently, in C++ the trick to declare the variable inside an expression
 essentially only works when we test against 0...

Sep 10 2003
prev sibling parent reply "Walter" <walter digitalmars.com> writes:
"Sean L. Palmer" <palmer.sean verizon.net> wrote in message
news:bjkuks$1spu$1 digitaldaemon.com...
 I prefer the "real" names:

 operator +
 operator []

Unfortunately, that doesn't work for things like reverse divide.
Sep 09 2003
next sibling parent reply Mike Wynn <mike l8night.co.uk> writes:
Walter wrote:
 "Sean L. Palmer" <palmer.sean verizon.net> wrote in message
 news:bjkuks$1spu$1 digitaldaemon.com...
 
I prefer the "real" names:

operator +
operator []

Unfortunately, that doesn't work for things like reverse divide.

class Foo { this() { } Foo operator rev_divide ( Foo f ) { .. } } although I'd rather see binary ops as static T operator op (T a, T b ) so there would be no need for sub/reverse_sub and unary ops as T operator op ( [optional params] ) {..} // [] is a unary op. where "op" is add, sub, etc are operators `virtual` or not ?
Sep 09 2003
parent "Walter" <walter digitalmars.com> writes:
"Mike Wynn" <mike l8night.co.uk> wrote in message
news:bjljc1$2rdb$1 digitaldaemon.com...
 are operators `virtual` or not ?

They're just like other functions, i.e. virtual.
Sep 09 2003
prev sibling next sibling parent "Sean L. Palmer" <palmer.sean verizon.net> writes:
This is why you make two versions, one with A on left and B on right, and
one with B on left and A on right.

I think you meant reverse subtract?

This is only a PITA if the operators are constrained to be member functions.
Then you gotta define one parm as "this".

Sean

"Walter" <walter digitalmars.com> wrote in message
news:bjlhbd$2odl$1 digitaldaemon.com...
 "Sean L. Palmer" <palmer.sean verizon.net> wrote in message
 news:bjkuks$1spu$1 digitaldaemon.com...
 I prefer the "real" names:

 operator +
 operator []

Unfortunately, that doesn't work for things like reverse divide.

Sep 10 2003
prev sibling parent reply "Riccardo De Agostini" <riccardo.de.agostini email.it> writes:
"Walter" <walter digitalmars.com> ha scritto nel messaggio
news:bjlhbd$2odl$1 digitaldaemon.com...
 "Sean L. Palmer" <palmer.sean verizon.net> wrote in message
 news:bjkuks$1spu$1 digitaldaemon.com...
 I prefer the "real" names:

 operator +
 operator []

Unfortunately, that doesn't work for things like reverse divide.

How about: operator ++ operator postfix ++ || postfix operator ++ || operator ++ postfix operator - operator reverse - || reverse operator - || operator - reverse operator / operator reverse / || reverse operator / || operator / reverse Did I (as almost usual ;-) ) overlook something? Ric
Sep 10 2003
parent reply "Walter" <walter digitalmars.com> writes:
"Riccardo De Agostini" <riccardo.de.agostini email.it> wrote in message
news:bjmsus$1kmm$1 digitaldaemon.com...
 "Walter" <walter digitalmars.com> ha scritto nel messaggio
 news:bjlhbd$2odl$1 digitaldaemon.com...
 "Sean L. Palmer" <palmer.sean verizon.net> wrote in message
 news:bjkuks$1spu$1 digitaldaemon.com...
 I prefer the "real" names:

 operator +
 operator []

Unfortunately, that doesn't work for things like reverse divide.

How about: operator ++ operator postfix ++ || postfix operator ++ || operator ++ postfix operator - operator reverse - || reverse operator - || operator - reverse operator / operator reverse / || reverse operator / || operator / reverse Did I (as almost usual ;-) ) overlook something?

That'll work, but it just doesn't look like much of an improvement :-( Anyhow, I'll think about it some more.
Sep 11 2003
parent "Riccardo De Agostini" <riccardo.de.agostini email.it> writes:
"Walter" <walter digitalmars.com> ha scritto nel messaggio
news:bjqhdm$ja4$3 digitaldaemon.com...
 That'll work, but it just doesn't look like much of an improvement :-(
 Anyhow, I'll think about it some more.

I certainly didn't even try to think how it would be implemented in the compiler... or you can be sure I'd have overlooked at least 80% of relevant issues, due to total inexperience in the field. But, from my perspective as a _user_ of compilers, this seems, more or less, the way to go (note that I've have little second thoughts with respect to my previous post): 1) the "operator" keyword makes code clearer at the first glance. This is maybe the only place where, IMHO, C++ looks better than D. To be truthful, I should also mention templates, but that's another story (and another thread). 2) Prefix and postfix ++ and -- need not be distinguished, _if_ in the postfix case you call the op-function immediately after evaluation of the subexpression containing the operator. So: if (++b > 42) would be the same as "b.operator ++(); if (b > 42)", while if (b++ > 42) would be the same as "bool temp = (b > 42); b.operator ++(); if (temp)" Again, I don't know if and how much this is practical for you as the compiler's author, but I see no use for two separate ++ operators, other than letting people hurt themselves... :) 3) For non-commutative binary operators, I see two possible ways: either a "reverse" attribute, with the same meaning as the "_r" suffix in current op-funcs, or not having them as members, so they take two parameters whose order is obviously specified in the declaration. 4) Following the same line of thinking, I'd suggest a "lvalue" attribute for the assignable index operator: "operator lvalue []" as opposed to "operator []" which does not (necessarily) return a lvalue. 5) a[3][5] and a[3, 5] are different beasts, I see no need for compiler intervention here. Hope I didn't forget anything this time. :) Ric
Sep 12 2003
prev sibling parent reply "Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> writes:
"Walter" <walter digitalmars.com> escreveu na mensagem
news:bjjd6g$2kvk$1 digitaldaemon.com...
 "Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> wrote in message
 news:bjj5bg$2ah0$1 digitaldaemon.com...

[snip]
 The other operator names are already nice (i.e. "add" instead of


 BTW will array operations be overloaded? Today the spec says:

Hmm. I kinda was thinking "add" was just a little too generic, that it

 need something to say it's a magic function to the compiler. Python sets

 the operator overloading with a __ prefix and postfix (which I find
 unattractive, but it does stand out).

So will you change "eq" and "cmp" too? If we're going to change them, it's better to change them all.
 a[] = b[] + 3;    =>  for (int i = 0; i < a.length; i++) { a[i] = b[i] +
 3; }
 But if I have a collection, will it work? I'm saying that because we'll

 to define some array-like data-structures (e.g. matrices, vector spaces)

 would be nice to have array operations (like Blitz++ has tensor


 Perhaps an "indices" operation could be used:


 a[] = b[] + 3;

 foreach (??? i; a.indices()) {a[i] = b[i] + 3; }

Since [] is a slice operation, I was thinking that this could be handled with the slice operator overload (having it return a different object,

 its own operator overloads).

If it's the way it would be nice to create a stride function too: a[1,3,5,7] = 0; // zeroes only the first four odd positions. Strides are nice to certain kinds of operations. Returning an intermediate object wouldn't bloat the code? The advantage of Blitz++ is that you don't have intermediate objects automagically appearing everywhere.
 Also it would be nice if I could define more than one index, so a matrix
 could be written:


 x = foo[i, j];        =>   x = foo.get(i, j);

 foo[i, j] = x;        =>   foo.set(i, j, x);

 foo[0 .. a, 0 .. b]   =>   foo.slice(0 .. a, 0 .. b);

Sean has some ideas along this line: x = foo[x][y]; => x = foo.get(x,y);

Won't this mean "foo.get(x).get(y)"? How will the compiler deal with vectors of vector: "vec[x][y]" will be "vec.get(x,y)" or "vec.get(x).get(y)". Also doesn't it make "(foo[x])[y]" an unexpected error? Best regards, Daniel Yokomiso. "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." - Buckminster Fuller --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.514 / Virus Database: 312 - Release Date: 28/8/2003
Sep 09 2003
parent reply "Walter" <walter digitalmars.com> writes:
"Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> wrote in message
news:bjlmcg$2vf1$1 digitaldaemon.com...
 So will you change "eq" and "cmp" too? If we're going to change them, it's
 better to change them all.

Yes, and you're right.
 Strides are nice to certain kinds of operations. Returning an intermediate
 object wouldn't bloat the code?

I don't know yet. Have to try it and see.
 Sean has some ideas along this line:
     x = foo[x][y];    => x = foo.get(x,y);


 of vector: "vec[x][y]" will be "vec.get(x,y)" or "vec.get(x).get(y)". Also
 doesn't it make "(foo[x])[y]" an unexpected error?

I was thinking that it could be disambiguated by looking for the existence of: get(int i, int j); vs: get(int i); It would take the longest one it found.
Sep 09 2003
parent reply "Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> writes:
----- Original Message ----- 
From: "Walter" <walter digitalmars.com>
Newsgroups: D
Sent: Wednesday, September 10, 2003 3:30 AM
Subject: Re: Array operator overloading
 "Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> wrote in message
 news:bjlmcg$2vf1$1 digitaldaemon.com...

[snip]
 Sean has some ideas along this line:
     x = foo[x][y];    => x = foo.get(x,y);


 of vector: "vec[x][y]" will be "vec.get(x,y)" or "vec.get(x).get(y)".


 doesn't it make "(foo[x])[y]" an unexpected error?

I was thinking that it could be disambiguated by looking for the existence of: get(int i, int j); vs: get(int i); It would take the longest one it found.

Hmmm, this kind of ad hoc parsing wasn't one of the things you were trying to get rid of? If we have "foo[x][y]" I'll probably want to write "bar = foo[x]; baz = bar[y];", but in this case it'll be an error, because "[]" isn't an operator, while "[][]" is. I prefer "foo[x,y]" because it's more concise and unambiguous. BTW I think it's an error to mix the syntax of true multi-dimensional arrays with ragged arrays, we should have true multi-dimensional arrays as a language feature and a ragged array is just a one-dimensional array of arrays: int[] foo; // one-dimensional array of ints int[,] bar; // bi-dimensional array of ints int[][] baz; // one-dimensional array of one-dimensional arrays of ints int[,,][,,,,][] qux; // guess what ;) If we make the syntax clearer will be easier for everyone to use it and the semantics will be clearer (probably the code will be more amenable to optimization). Best regards, Daniel Yokomiso. "If at first you succeed try not to look astonished." --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.514 / Virus Database: 312 - Release Date: 28/8/2003
Sep 11 2003
parent reply "Walter" <walter digitalmars.com> writes:
"Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> wrote in message
news:bjpj65$2b1u$1 digitaldaemon.com...
 It would take the longest one it found.

to get rid of?

Yes. I don't like it either.
 If we have "foo[x][y]" I'll probably want to write "bar =
 foo[x]; baz = bar[y];", but in this case it'll be an error, because "[]"
 isn't an operator, while "[][]" is. I prefer "foo[x,y]" because it's more
 concise and unambiguous. BTW I think it's an error to mix the syntax of

 multi-dimensional arrays with ragged arrays, we should have true
 multi-dimensional arrays as a language feature and a ragged array is just

 one-dimensional array of arrays:


 int[] foo;   // one-dimensional array of ints
 int[,] bar;  // bi-dimensional array of ints
 int[][] baz; // one-dimensional array of one-dimensional arrays of ints

 int[,,][,,,,][] qux; // guess what ;)


     If we make the syntax clearer will be easier for everyone to use it

 the semantics will be clearer (probably the code will be more amenable to
 optimization).

I guess I'm just so used to the C version of things. I don't know what the right answer is, I'll think about it some more.
Sep 11 2003
parent reply Mike Wynn <mike l8night.co.uk> writes:
Walter wrote:
 "Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> wrote in message
 news:bjpj65$2b1u$1 digitaldaemon.com...
 
It would take the longest one it found.

Hmmm, this kind of ad hoc parsing wasn't one of the things you were trying to get rid of?

Yes. I don't like it either.
If we have "foo[x][y]" I'll probably want to write "bar =
foo[x]; baz = bar[y];", but in this case it'll be an error, because "[]"
isn't an operator, while "[][]" is. I prefer "foo[x,y]" because it's more
concise and unambiguous. BTW I think it's an error to mix the syntax of

true
multi-dimensional arrays with ragged arrays, we should have true
multi-dimensional arrays as a language feature and a ragged array is just

a
one-dimensional array of arrays:


int[] foo;   // one-dimensional array of ints
int[,] bar;  // bi-dimensional array of ints
int[][] baz; // one-dimensional array of one-dimensional arrays of ints

int[,,][,,,,][] qux; // guess what ;)


    If we make the syntax clearer will be easier for everyone to use it

and
the semantics will be clearer (probably the code will be more amenable to
optimization).

I guess I'm just so used to the C version of things. I don't know what the right answer is, I'll think about it some more.

much as I like the idea of multi-dim arrays being passable, I can forsee someone wanting to pass an N dim array int func( int[,*] f ) { if f.dimensions = 1 .... etc } I think if nothing more this is another reason that growable array should be a templated class, the only think D offers is "block" which can be sliced same syntax as now just no ~=/~ operator on T[] func( T[] f ) { ... same as now arrays are passed with their length. } however with the operator overloading each [] is a call to operator_index foo[a][b] => foo.operator_index(a).operator_index(b) foo[a,b] => foo.operator_index(a,b) foo[a,b][c,d] => foo.operator_index(a,b).operator_index(b,c) either disallow range or pass as a Range object foo[a] => calls foo::operator_index( a.type ) foo[a..b] => calls foo::operator_index( Range ) or calls foo.operator_index( foo.operator_create_range(a, b) ); index then called with the return type from create_range which might be anything. foo[a..b][d] => foo.operator_index( new range(a,b) ).operator_index(d) ranges seem to me to be leading up the c++ path, where although you can overload x,y,z the performance penalty grows with the ease programing/flexability. I think most uses of range are covered by just allowing one use foo[a..b] => operator_slice( int a, int b ) I'm happy to have class My2Obj { int[] operator_index( int a ) { .... } } My2Obj foo; foo[a][b] => foo.operator_index(a).operator_index(b) which is foo.operator_index(a)[b] template array( T ) { class Ar2D { T[] ar; this( int xw, int yw ) { ar = new T[xw*yw]; sw = xw; } int[] operator_index( int a ) { return ar[(a*sw)..(a*sw+sw)] } int operator_index( int a, b ) { return ar[a+(b*sw)] } } alias instance array(int).Ar2D myblock; myBlock foo = new myBlock( xm, ym ); foo[y][x] now equiv to foo[x,y] you can do foo[y] and it behaves like bar = new int[xm][ym]; only bar should be a true array of arrays. that goes for int[4][5] b; should create array of arrays not a single block just a bit of syntactic sugar. what about "put" ? we still need a put to do a hashtable (I like the syntax of assoc arrays, but think they should be classes not primatives) template array( T, M ) { class Hashtable { class Entry { M key; T val; Entry next; } Entry[] ar; this() { } T operator_index( M a ) { return find_in_chain( ar[a.hashcode%ar.length], a ); } }
Sep 11 2003
parent Felix <Felix_member pathlink.com> writes:
Hi,

I don't want to disturb you, guys. But I am working a lot in Matlab and it has
some nice features for arrays (I think they are the best):

-arrays are multidimensional and are indexed as a[2,4,5] (example to select an
element);
-syntax like a[:,3] will select all the third column of the matrix a;
-a[:] will concatenate all the columns of a into 1 column vector;
-a*b is standard matrix multiplication while a.*b is multiplying element by
element;
-the same stands for a^2 and a.^2;
-a[4:end] will select the elements from 4 to the end of the vector (no matter
how long);
-and more...

Only to give you an ideea.


Felix

PS Yes, Matlab is an interpreter, but all the code can be compiled in C. (eh,
almost, no objects available for that).







In article <bjr184$196c$1 digitaldaemon.com>, Mike Wynn says...
Walter wrote:
 "Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> wrote in message
 news:bjpj65$2b1u$1 digitaldaemon.com...
 
It would take the longest one it found.

Hmmm, this kind of ad hoc parsing wasn't one of the things you were trying to get rid of?

Yes. I don't like it either.
If we have "foo[x][y]" I'll probably want to write "bar =
foo[x]; baz = bar[y];", but in this case it'll be an error, because "[]"
isn't an operator, while "[][]" is. I prefer "foo[x,y]" because it's more
concise and unambiguous. BTW I think it's an error to mix the syntax of

true
multi-dimensional arrays with ragged arrays, we should have true
multi-dimensional arrays as a language feature and a ragged array is just

a
one-dimensional array of arrays:


int[] foo;   // one-dimensional array of ints
int[,] bar;  // bi-dimensional array of ints
int[][] baz; // one-dimensional array of one-dimensional arrays of ints

int[,,][,,,,][] qux; // guess what ;)


    If we make the syntax clearer will be easier for everyone to use it

and
the semantics will be clearer (probably the code will be more amenable to
optimization).

I guess I'm just so used to the C version of things. I don't know what the right answer is, I'll think about it some more.

much as I like the idea of multi-dim arrays being passable, I can forsee someone wanting to pass an N dim array int func( int[,*] f ) { if f.dimensions = 1 .... etc } I think if nothing more this is another reason that growable array should be a templated class, the only think D offers is "block" which can be sliced same syntax as now just no ~=/~ operator on T[] func( T[] f ) { ... same as now arrays are passed with their length. } however with the operator overloading each [] is a call to operator_index foo[a][b] => foo.operator_index(a).operator_index(b) foo[a,b] => foo.operator_index(a,b) foo[a,b][c,d] => foo.operator_index(a,b).operator_index(b,c) either disallow range or pass as a Range object foo[a] => calls foo::operator_index( a.type ) foo[a..b] => calls foo::operator_index( Range ) or calls foo.operator_index( foo.operator_create_range(a, b) ); index then called with the return type from create_range which might be anything. foo[a..b][d] => foo.operator_index( new range(a,b) ).operator_index(d) ranges seem to me to be leading up the c++ path, where although you can overload x,y,z the performance penalty grows with the ease programing/flexability. I think most uses of range are covered by just allowing one use foo[a..b] => operator_slice( int a, int b ) I'm happy to have class My2Obj { int[] operator_index( int a ) { .... } } My2Obj foo; foo[a][b] => foo.operator_index(a).operator_index(b) which is foo.operator_index(a)[b] template array( T ) { class Ar2D { T[] ar; this( int xw, int yw ) { ar = new T[xw*yw]; sw = xw; } int[] operator_index( int a ) { return ar[(a*sw)..(a*sw+sw)] } int operator_index( int a, b ) { return ar[a+(b*sw)] } } alias instance array(int).Ar2D myblock; myBlock foo = new myBlock( xm, ym ); foo[y][x] now equiv to foo[x,y] you can do foo[y] and it behaves like bar = new int[xm][ym]; only bar should be a true array of arrays. that goes for int[4][5] b; should create array of arrays not a single block just a bit of syntactic sugar. what about "put" ? we still need a put to do a hashtable (I like the syntax of assoc arrays, but think they should be classes not primatives) template array( T, M ) { class Hashtable { class Entry { M key; T val; Entry next; } Entry[] ar; this() { } T operator_index( M a ) { return find_in_chain( ar[a.hashcode%ar.length], a ); } }

Sep 11 2003
prev sibling parent reply Patrick Down <pat codemoon.com> writes:
"Walter" <walter digitalmars.com> wrote in
news:bjhefn$2qdb$1 digitaldaemon.com: 

 I'm thinking that the following operator overload functions will cover
 the territory. Have I missed anything?
 
 x = foo[y];    =>   x = foo.opIndex(y);
 
 foo[y] = x;    =>   foo.opIndexAss(y, x);
 
 foo[a .. b]     =>   foo.opSlice(a, b);
 
 And yes, I think the other operator overloads should be renamed with
 an "op" prefix.
 
 

I like this approach for the indexing operator. I don't have a big opinion on the exact function names but I'm in the op_add, op_mul, op_whatever camp. I would like to have multidimensional indexing and slicing too. I prefer the array[x,y] syntax. I don't think that you need to support it as a basic feature of D arrays but it would be nice to define classes that would support it.
Sep 11 2003
next sibling parent "Walter" <walter digitalmars.com> writes:
"Patrick Down" <pat codemoon.com> wrote in message
news:Xns93F3E63E057FBpatcodemooncom 63.105.9.61...
 I would like to have multidimensional indexing and slicing too.  I
 prefer the array[x,y] syntax.  I don't think that you need to support
 it as a basic feature of D arrays but it would be nice to define classes
 that would support it.

That might be a good compromise.
Sep 11 2003
prev sibling parent "Matthew Wilson" <matthew stlsoft.org> writes:
 I like this approach for the indexing operator.  I don't have a big
 opinion on the exact function names but I'm in the op_add, op_mul,
 op_whatever camp.

I've revised my antipathy to ambiguousness upwards, and now will be unhappy with anything less than the Python-esque __op_add__, __op_index_l__, etc. I'm not holding my breath ... ;(
Sep 12 2003