Two Dimensional Array Template

N

Noah Roberts

Gianni said:
Apart from vector<bool>, this IS the C++ standard for std::vector. As
for Array2D<T>, I suppose you can return a proxy that gens a
std::vector<T>::reference_type instead of a pointer and there would be
no need to specialize Array2D. Still, if you don't need a <bool>
implementation, let's not make the OP worry about it.

Frankly I don't think vector<bool> should exist, at least not any
differently than any other type of vector. It throws a wrench into the
whole works and makes it impossible to create a real vector<bool>.
 
D

Daniel T.

Gianni Mariani said:
I can show an implementation of [][] that calls call your (,) and most
compilers will optimize it so there is nothing different between calling
(,) or [][].

By all means, do so. Really, I'm interested in seeing it. If you can
show one that still uses the interface shown by Peter, I'll be very
surprised.
The FAQ is guilty of being a proponent of inventing a new syntax where
none in needed IMHO.

Now, if I create a bunch o 2D array templates, they will work fine with
both the new Array2D or a native 2D array. Do that with the (,) syntax!

I don't believe there is a "native 2D array" in C++, if there is, please
reference where in the standard it is specified.

Regardless, if you can show an interface that can work for "native 2D
arrays", row-major, column-major and sparse arrays, then you will have
taught me something very cool. I'd love to see it.
 
N

Noah Roberts

Gianni said:
Now, if I create a bunch o 2D array templates, they will work fine with
both the new Array2D or a native 2D array. Do that with the (,) syntax!

That is the only strength it has over () while suffering deficiencies
already iterated many times in this group and in the FAQ. _If_
backwards compatibility is the single most important issue you face
then it is probably appropriate to mimic a compatible interface.
Otherwise I think the other issues far outweigh this one, narrow
requirement.
It's just easier all the way around.

Only given a very specific set of needs...not "all the way around."
 
G

Gianni Mariani

Noah Roberts wrote:
....
Frankly I don't think vector<bool> should exist, at least not any
differently than any other type of vector. It throws a wrench into the
whole works and makes it impossible to create a real vector<bool>.

I agree - but that is what the standard is.
 
N

Noah Roberts

Daniel said:
Regardless, if you can show an interface that can work for "native 2D
arrays", row-major, column-major and sparse arrays, then you will have
taught me something very cool. I'd love to see it.

Simply returning a "row_reference" from operator[] that itself has an
operator[] will allow you to do these things. It's just a might bit
more complex than the alternative and thus is a less optimal solution
unless truely needed.

class col_mjr_mtx
{
...
reference_type ref(int x, int y);
row_reference operator[](int x) { return rowref<col_mjr_mtx>(this, x);
}
};

template < typename T >
class rowref
{
T * mtx;
int row;

public:
...
typename T::reference_type operator[](int y) { return mtx->ref(row,
y); }
};

See, no big deal but is most easily implemented in terms of a function
or functor op call.
 
G

Gianni Mariani

Daniel said:
I don't believe there is a "native 2D array" in C++, if there is, please
reference where in the standard it is specified.

Here:
T x[2][2];
Regardless, if you can show an interface that can work for "native 2D
arrays", row-major, column-major and sparse arrays, then you will have
taught me something very cool. I'd love to see it.

<brain dump - be warned>

template <typename T>
class array2d
{
..... I'll let someone else fill in the blanks ...
..... const/non_const constructors etc ....

T & operator()( int, int );

deref_proxy operator[]( int i )
{
return deref_proxy( i, * this );
}

class deref_proxy
{
int i;
array2d & a;
inline deref_proxy( int ii, array2d & ia )
: i( ii ), a( ia )
{
}
public:
inline T & operator[]( int j )
{
return a(j,i);
}
};
};

In a micro-detail perspective, what the proxy does is collect the
arguments to the (,) call and calls it when it has all the info. Tests
I did a while back with popular compilers is that the assembly code
generated is identical. The proxy has no overhead whatsoever.

Hence, anything that can implemented with (,) I can also implement with
[][] with negligible if any performance issues. QED.
 
D

Daniel T.

Gianni Mariani said:
Daniel said:
I don't believe there is a "native 2D array" in C++, if there is, please
reference where in the standard it is specified.

Here:
T x[2][2];

How is that a reference in the standard? I don't believe the C++
standard defines multi-dimensional arrays at all. I may be wrong on this
point and if so, someone please correct me.
<brain dump - be warned>
[snipped brain dump]

Now it is me who should have read the FAQ. :) The procedure you
outlined is exactly what the FAQ recommends in item 13.12.

However, you have needlessly complicated your class simply to support a
particular syntax. It seems that for you, it *is* all about the syntax,
and you are willing to jump through a few hoops to support that syntax.
For me, if presented with a class like your array2d, I'll just call the
(,) directly rather than going through the proxy.

One last note, your array2d with proxy still doesn't support the
"native" 2d syntax... The below doesn't compile.

void foo( int b[] );

int main() {
array2d<int> a( 10, 10 );
foo( a[3] );
}

So the reason you are supporting this particular syntax (so it will work
like "native" 2d arrays) doesn't fly.
 
G

Gianni Mariani

Daniel said:
Gianni Mariani said:
Daniel said:
I don't believe there is a "native 2D array" in C++, if there is, please
reference where in the standard it is specified.

Here:
T x[2][2];

How is that a reference in the standard? I don't believe the C++
standard defines multi-dimensional arrays at all. I may be wrong on this
point and if so, someone please correct me.

I don't you're making a distiction that has any relevant consequences.
Clearly multi-dimensional arrays have been implemented as arrays of
arrays for many years. Having a semantic argument about arrays of
arrays vs multi-dimensional arrays does not help your (,) argument.
The rule is that [][] is far more common than (,) for writing matrix
code.
<brain dump - be warned>
[snipped brain dump]

Now it is me who should have read the FAQ. :) The procedure you
outlined is exactly what the FAQ recommends in item 13.12.

However, you have needlessly complicated your class simply to support a
particular syntax. It seems that for you, it *is* all about the syntax,
and you are willing to jump through a few hoops to support that syntax.
For me, if presented with a class like your array2d, I'll just call the
(,) directly rather than going through the proxy.

Let's see if we disagree on any of these statements:

a) in C and in C++ matricies have been traditionally supported using
[][] (array of array) syntax. Hence there is a non-trivial body of
code and knowledge that is using [][] as opposed to (,).

b) Because of proxy classes, [][] is exactly equivalent in
functionality to (,) or perhaps even a superset. (BTW, I did confirm
again on gcc that the proxy class [][] creates exactly the same
instructions as (,). - I have attached the code example below).

c) Many standard matrix operations will be coded in templates
(multiples, inverses etc).

d) Many of these "matrix" templates can be used to operate on legacy C
and C++ code as well as newer code using proxy (or non proxy array
classes like the OP code) using [][].

Having shown what a proxy class might look like, you will see that all
the arguments in the FAQ (yes - all of them) supporting (,) have no
supportable rationale at all. Perhaps it's one of the most
short-sighted sections of the entire FAQ.

No generality at all is lost using [][] over (,) while the visa versa
statement is NOT true. (,) loses in 2 very significant ways.

1) new functions on older code
2) new learning curve for no real gain

I'll say it again, anying (,) can do [][] can do better.

You say "needlessly" complicated ? The complexity is in ONE place and
makes most other code easier to read. This is a Good(TM) tradeoff.
Needlessly changing a body of code using [][] to (,) is far more
complex. It's also not exactly a complex concept. Proxy classes are a
very easy concept to understand and code - after all it's only 20 lines
in this example.
One last note, your array2d with proxy still doesn't support the
"native" 2d syntax... The below doesn't compile.

void foo( int b[] );

int main() {
array2d<int> a( 10, 10 );
foo( a[3] );
}

So the reason you are supporting this particular syntax (so it will work
like "native" 2d arrays) doesn't fly.

That would be easy to support using a conversion operator, however we
may or may not want to support that. That depends on the design goals
of the matrix class.

Regardless, if you really wanted to perform such operations, you can,
with constraints and contstaint violations can be compile time errors
that give you assurances that any code that does compile will do as
expected and any code that violates constraints never issues an
instruction.

------------The return of the proxy code---------

// on a FC5 machine using gcc, the instructions for the x() and y()
// functions emitted by the compiler are identical for
// optimization levels O1 and above on both IA32 and AMD64
// architectures.

template <typename T>
class array2d
{
public:

T & operator()( int, int );

class deref_proxy;

inline deref_proxy operator[]( int i )
{
return deref_proxy( i, * this );
}

class deref_proxy
{
const int i;
array2d & a;
public:
inline deref_proxy( const int ii, array2d & ia )
: i( ii ), a( ia )
{}
public:
inline T & operator[]( int j )
{
return a(i,j);
}
};

};


float y( array2d<float> & a, int i, int j )
{
return a(i,j);
}

float x( array2d<float> & a, int i, int j )
{
return a[j];
}
 
G

Gianni Mariani

Noah said:
That is the only strength it has over () while suffering deficiencies
already iterated many times in this group and in the FAQ.

Not one of the arguments supporting the use of (,) only in the FAQ is
supportable with a coherent rationale.

As I have shown earlier in this thread, [][] and (,) are exactly the
same in funtionalitly and performance while [][] can also be a superset
if need be.
... _If_
backwards compatibility is the single most important issue you face
then it is probably appropriate to mimic a compatible interface.
Otherwise I think the other issues far outweigh this one, narrow
requirement.

That's where we disagree. There are no other issues IMHO.
 
G

Gianni Mariani

Simon G Best wrote:
....
But let me ask you a question. If you use C-style subscripting, with
operator[], to access a whole row, then what do you use to access a
whole column?

Whatever you like !

a.Col(n)
a[COL+n]
a.Transpose()[n]
^a[n]
a++[n]

..... or don't provide one at all ...

Whatever tickles your fancy.
 
S

Simon G Best

Daniel said:
Gianni Mariani said:
Daniel T. wrote: ....
<brain dump - be warned>
[snipped brain dump]

Now it is me who should have read the FAQ. :) The procedure you
outlined is exactly what the FAQ recommends in item 13.12.

The idea behind that proxy technique is obvious once you dig closures :)

http://en.wikipedia.org/wiki/Closure_(computer_science)

I like to think of closures as being what you get when you call
functions taking two or more arguments, but without passing all the
arguments they need, yet. Sort of like unfinished function invocations.
You end up with a function taking the remaining arguments, so that you
can finish invoking it later. Of course, in C++, you have to actually
define appropriate classes for this, rather than do it with normal
functions.

[Start C++ snippet.]

double foo (int, double);

class foo_closure_1 {
int a;

public:
explicit foo_closure_1 (int arg1): a(arg1) {}
double operator() (double arg2) const { return foo(a, arg2); }
};

class foo_closure_2 {
double a;

public:
explicit foo_closure_2 (double arg2): a(arg2) {}
double operator() (int arg1) const { return foo(arg1, a); }
};

foo_closure_1 foo (int arg1) { return foo_closure_1(arg1); }
foo_closure_2 foo (double arg2) { return foo_closure_2(arg2); }

double bar () {
foo_closure_1 foo1 = foo(42);
foo_closure_2 foo2 = foo(37.361);
return foo1(foo2(8));
}

[End C++ snippet.]

:-D

Back to two-dimensional arrays and proxies, there's a few things I'd
like to add:-

* We don't have to choose between [][] and (,); we can have both. If
we have both, it'll work with code that expects a [][] interface and
code that expects a (,) interface.

* We can have both row() and col() member functions as well, returning
corresponding row_reference and col_reference proxies. So, as well as
being able to access whole rows, we can also access whole columns,
regardless of how the array is actually implemented internally. (We
could have things like transpose proxies, as well.)

* We can have row and column iterators.

* When we need to apply a generic algorithm to a row or column, and
that algorithm's interface is for one-dimensional array-like things, we
can use the appropriate row or column proxy to present that algorithm
with an appropriate interface to the data.

* Having row() and col(), and the like, as part of the interface,
rather than just having (,), saves others from having to write their own
wrappers when they need to do this proxy type stuff.

* If we do a sufficiently good job of it, we'll be able to use it on
many occasions when two-dimensional arrays are needed, instead of
reimplementing them all the time. So it really doesn't matter that this
proxy stuff takes a bit more work to implement, because it's potentially
a lot more work saved in the long run!

:)

Simon
 
G

Gianni Mariani

This one is going to Marshall Cline as well, the maintainer of the FAQ
as well as to the news-group.
Peter Olcott said:
http://groups.google.com/group/comp.lang.c++/msg/a9092f0f6c9bf13a

I think that the operator[]() member function does not work
correctly, does anyone else know how to make a template for making
two dimensional arrays from std::vectors ?
http://www.parashift.com/c++-faq-lite/operator-overloading.html#faq-13.10

I want to use normal Array[ROW][COL] Syntax.

Why?

It's time to change the FAQ 13.10/13.11/13.12

Let's look at it in more detail:

13.10 provides no reasoning for the advice "Use operator() rather than
operator[]." and leaves all the heavy lifting of reasoning to 13.11.

............ FAQ13.11 says: ............

P1 Here's what this FAQ is really all about: Some people build a Matrix
class that has an operator[] that returns a reference to an Array object
(or perhaps to a raw array, shudder), and that Array object has an
operator[] that returns an element of the Matrix (e.g., a reference to a
double). Thus they access elements of the matrix using syntax like
m[j] rather than syntax like m(i,j).

P2 The array-of-array solution obviously works, but it is less flexible
than the operator() approach. Specifically, there are easy performance
tuning tricks that can be done with the operator() approach that are
more difficult in the [][] approach, and therefore the [][] approach is
more likely to lead to bad performance, at least in some cases.

P3 For example, the easiest way to implement the [][] approach is to use
a physical layout of the matrix as a dense matrix that is stored in
row-major form (or is it column-major; I can't ever remember). In
contrast, the operator() approach totally hides the physical layout of
the matrix, and that can lead to better performance in some cases.

P4 Put it this way: the operator() approach is never worse than, and
sometimes better than, the [][] approach.

* The operator() approach is never worse because it is easy to
implement the dense, row-major physical layout using the operator()
approach, so when that configuration happens to be the optimal layout
from a performance standpoint, the operator() approach is just as easy
as the [][] approach (perhaps the operator() approach is a tiny bit
easier, but I won't quibble over minor nits).

* The operator() approach is sometimes better because whenever the
optimal layout for a given application happens to be something other
than dense, row-major, the implementation is often significantly easier
using the operator() approach compared to the [][] approach.

P5 As an example of when a physical layout makes a significant
difference, a recent project happened to access the matrix elements in
columns (that is, the algorithm accesses all the elements in one column,
then the elements in another, etc.), and if the physical layout is
row-major, the accesses can "stride the cache". For example, if the rows
happen to be almost as big as the processor's cache size, the machine
can end up with a "cache miss" for almost every element access. In this
particular project, we got a 20% improvement in performance by changing
the mapping from the logical layout (row,column) to the physical layout
(column,row).

P6 Of course there are many examples of this sort of thing from
numerical methods, and sparse matrices are a whole other dimension on
this issue. Since it is, in general, easier to implement a sparse matrix
or swap row/column ordering using the operator() approach, the
operator() approach loses nothing and may gain something — it has no
down-side and a potential up-side.

Use the operator() approach.
........... end 13.11 FAQ ..........

Let's see if we can make any sense of this given what has been discussed
many times:

P1 - no advice given

P2 - claims that
a) [][] is less flexible than (,)
b) [][] is lower performance because of a)

P3 - discusses one possible implementation of [][] and claims that (,)
can use performance tricks and so is better that [][].

P4 - states that (,) is never worse than [][] because:
a) it is easier to implement different layouts in (,) than [][]
b) layouts other than dense row-major are not available for [][]

P5 - explains example of changing matrix layouts, says nothing about
[][] vs (,) specifically.

P6 - claims again that (,) is more flexible than [][].


As you can see, the FAQ bases all the claims on the false assumption
that by using [][], you cannot implement optimizations using (,). As
has been shown many times before and again elsewhere in this thread and
also in FAQ 13.12, [][] can be used to call an (,) functor with no
performance penalty and hence can enjoy the same performance tuning and
tweaks as (,). Then the question remains, why employ the (,) syntax at
all since the only claim made in the 13.11FAQ is absolutely false?

Clearly, multi-dimensional array, matricies or whaterver your favorite
name is for these things has been traditionally the [][] flavour. There
is also clearly a non trivial amount of code and expertise using the
[][] type syntax and there is clearly no confusion about what X[a]
means when written in code.

Also, properly written function templates will easily work with native
array-of-array (in much the same way as STL containers work with the []
syntax) as well as special matrix classes. Hence that body of template
functions for matrix manipulations will work with new and old code.
Exactly the same way that std::sort works with containers as well as raw
arrays of objects.

Let's enumerate the reasons for [][].

1. [][] syntax is well understood by C++ programmers for manipulating
multi-dimensional properties. No surprises here !
2. X[a] will never be confused like X(a,b) as a function call to
function X.
3. Legacy code can make use of modern templates using the [][] syntax
while converting legacy code to (,) would need major code surgery.
4. array2D[a] is syntactic sugar for a row reference and can be used to
optimize accesses.

The 13.11 FAQ states NO justifiable reasons to use (,) at all since it
is all based on the premise that (,) is "more flexible" than [][] which
has been debunked by the FAQ itself as well as others. The only reason
even close to having merit is that (,) does not expose any internal
working, the question is, how much merit do you give this one since the
row reference proxy need not expose anything anyway.

It's time to change 13.10 to recommend the use of the [][] syntax since
in my opinion which is shared by others, there is no good reason to use (,).

OK - while we are at it, the code in the matrix class in 13.10 should
not throw "BadIndex", it should assert. Indexing beyond the bounds of
an array is a fatal error and the program should be aborted.

Any talk of the (,) syntax in the future FAQ should be as a history
lesson, not as a recommendation.
 
D

Daniel T.

Gianni Mariani said:
Let's see if we disagree on any of these statements:

a) in C and in C++ matricies have been traditionally supported using
[][] (array of array) syntax. Hence there is a non-trivial body of
code and knowledge that is using [][] as opposed to (,).

I disagree. [][] is used extensively in C, but in C++ I believe that
most code involving matrices uses some sort of matrix class.
b) Because of proxy classes, [][] is exactly equivalent in
functionality to (,) or perhaps even a superset.

Here I agree. Which is why I said it is purely a matter of syntax for
you. You are so married to the [][] that you just can't let it go even
though implementing a class that can support it is more complex than
implementing a class that supports (,)
c) Many standard matrix operations will be coded in templates
(multiples, inverses etc).

d) Many of these "matrix" templates can be used to operate on legacy
C and C++ code as well as newer code using proxy (or non proxy array
classes like the OP code) using [][].

As I and others have mentioned before, if you have a bunch of legacy
code that you need to support then that is sufficient justification to
use the [][] syntax.

That is not sufficient justification to continue using it in an
environment where legacy code need not be supported. A perfect example
is the use of std::vector. It is acceptable and understood that legacy
code will use [] to access elements in a vector, but new code really
should use iterators.
Having shown what a proxy class might look like, you will see that
all the arguments in the FAQ (yes - all of them) supporting (,) have
no supportable rationale at all.

I disagree. The fact that you used proxy classes to convert [][] into
(,) shows that all of the arguments in the FAQ are right on the mark.
Hence the reason you chose to use (,) "under the covers".
Perhaps it's one of the most short-sighted sections of the entire
FAQ.

Again I disagree. The most short-sighted section is the one talking
about using declarations. :)
No generality at all is lost using [][] over (,) while the visa
versa statement is NOT true. (,) loses in 2 very significant ways.

1) new functions on older code
2) new learning curve for no real gain

Number (1) above has already been accepted and specifically mentioned in
the FAQ. Number (2) is just plain silly. The learning curve on proper
proxy creation is sharper than the learning curve involved in changing
syntax.
You say "needlessly" complicated ? The complexity is in ONE place
and makes most other code easier to read. This is a Good(TM)
tradeoff.

I disagree. The complexity exists in more than one place--it must exist
in every class that implements a multi-dimensional array--and most other
code is no easier to read--a programmer that can't grep the (,) syntax
instantly, doesn't understand function calls.
Needlessly changing a body of code using [][] to (,) is far more
complex. It's also not exactly a complex concept.

Again, your only argument that holds any water involves legacy code and
the FAQ has already excepted that case.
 
G

Gianni Mariani

Daniel said:
Gianni Mariani said:
Let's see if we disagree on any of these statements:

a) in C and in C++ matricies have been traditionally supported using
[][] (array of array) syntax. Hence there is a non-trivial body of
code and knowledge that is using [][] as opposed to (,).

I disagree. [][] is used extensively in C, but in C++ I believe that
most code involving matrices uses some sort of matrix class.

I have never seen production code use (,) for array indexing.
.... much snipped.
Having shown what a proxy class might look like, you will see that
all the arguments in the FAQ (yes - all of them) supporting (,) have
no supportable rationale at all.

I disagree. The fact that you used proxy classes to convert [][] into
(,) shows that all of the arguments in the FAQ are right on the mark.
Hence the reason you chose to use (,) "under the covers".

You misunderstand my intention for writing that class. I made that proxy
class to make a point that anything you can do with (,) you can do with
[][]. That was it's only purpose.

....
No generality at all is lost using [][] over (,) while the visa
versa statement is NOT true. (,) loses in 2 very significant ways.

1) new functions on older code
2) new learning curve for no real gain

Number (1) above has already been accepted and specifically mentioned in
the FAQ. Number (2) is just plain silly. The learning curve on proper
proxy creation is sharper than the learning curve involved in changing
syntax.

I think you severely underestimate the familiarity programmers have with
[][] and the foreign nature of (,).
I disagree. The complexity exists in more than one place--it must exist
in every class that implements a multi-dimensional array--and most other
code is no easier to read--a programmer that can't grep the (,) syntax
instantly, doesn't understand function calls.

The (,) syntax is usually called a "functor", not a "subscript"
operator. It is clearly the intention of the language designers that
[][] be used to access arrays and (,) used to call a functor. It
appears strange to me why you would ever want to use a functor when a
subscript operator is clearly intended for it's purpose.
Needlessly changing a body of code using [][] to (,) is far more
complex. It's also not exactly a complex concept.

Again, your only argument that holds any water involves legacy code and
the FAQ has already excepted that case.

Why would I ever want to build a body of code that would exclude the
largest set of customers ? Legacy code using [][] syntax is here for a
very very long time. There really should be a very solid reason to
deviate. All the reasons given so far to use (,) in preference to [][]
hold no water IMHO.
 
D

Daniel T.

[from the faq]
Here's what this FAQ is really all about: Some people build a
Matrix class that has an operator[] that returns a reference to
an Array object (or perhaps to a raw array, shudder), and that
Array object has an operator[] that returns an element of the
Matrix (e.g., a reference to a double). Thus they access
elements of the matrix using syntax like m[j] rather than
syntax like m(i,j).


The above is what I think we have both lost sight of. Peter initially
posted code that did exactly what the above paragraph talks about and I
agreed with the FAQ about the inappropriateness of it. When I asked you
to present an appropriate example that uses the [][] syntax, you
proceeded to present one that is specifically marked as acceptable by
the FAQ.

It is important to note that the FAQ is not comparing two syntaxes, but
two implementations. On the one hand having an op[] that returns a
reference to an array object or a raw array (something I think we can
both agree is a bad idea,) on the other hand not doing so.
 
D

Daniel T.

Gianni Mariani said:
This one is going to Marshall Cline as well, the maintainer of the FAQ
as well as to the news-group.

He is not the maintainer of this newsgroup. This is not a moderated
forum. By all means though, send it to him. I have found him very
accessible in the past.
 
L

Lionel B

Daniel said:
Gianni Mariani said:
Let's see if we disagree on any of these statements:

a) in C and in C++ matricies have been traditionally supported using
[][] (array of array) syntax. Hence there is a non-trivial body of
code and knowledge that is using [][] as opposed to (,).

I disagree. [][] is used extensively in C, but in C++ I believe that
most code involving matrices uses some sort of matrix class.

I have never seen production code use (,) for array indexing.

I have written much production code using (,) for array indexing (you
won't see it however, as it is closed-source and owned by the various
companies I worked for :/).

[snip]
I think you severely underestimate the familiarity programmers have with
[][] and the foreign nature of (,).

Not so sure about that... one class of programmers for whom (,) will be
second nature are scientific/mathematical (and in particular
[ex-]Fortran) programmers. In mathematics an array/matrix is not
generally perceived as a "vector-of-vectors" (except when it is...) and
the (,) notation sits fine with me (okay, so I *am* an ex-Fortran
programmer :))

Personally I'm comfortable with either notation and concur with Daniel T.
that the only legitimate reason - albeit possibly a significant one - for
using the [][] syntax is legacy code support. So notwithstanding your
demonstration that the two approaches may be made functionally equivalent
via proxy classes, I'll go with the simpler implementation and (to me)
marginally preferable syntax of (,).

[snip]
The (,) syntax is usually called a "functor", not a "subscript"
operator.

He didn't say "subscript operator", he said "function calls"... and a
"functor" operator is of course a function, as is a "subscript
operator". If, as a C++ programmer round brackets don't scream "function"
to you, you're surely in trouble... whatever other conceptual baggage
(functor, subscript operator,...) you care to attach to a particular
function comes after that fact.
It is clearly the intention of the language designers that
[][] be used to access arrays

Which language? C? ;)

[snip]
 
N

Noah Roberts

Gianni said:
The (,) syntax is usually called a "functor", not a "subscript"
operator. It is clearly the intention of the language designers that
[][] be used to access arrays and (,) used to call a functor. It
appears strange to me why you would ever want to use a functor when a
subscript operator is clearly intended for it's purpose.

Well, if you want to go there...basing arguments of design on what the
language designers intended...then forcing [][] on a class has no place
in any code since if the language designers had intended a class to
override [][] they would have provided the means to do so.
Needlessly changing a body of code using [][] to (,) is far more
complex. It's also not exactly a complex concept.

Again, your only argument that holds any water involves legacy code and
the FAQ has already excepted that case.

Why would I ever want to build a body of code that would exclude the
largest set of customers ? Legacy code using [][] syntax is here for a
very very long time.

Only so long as it is not changed. I work on legacy code every
day...some of the nastiest stuff ever written at times. It is rather
easy work, though boring, to change function call signatures and go
from [] to f(). I know this because I do it every day. So unless you
are selling a library that has a bunch of legacy code based on it you
don't need to worry about it...and as you showed, you can always
implement the deprecated interface for those that do if you are in such
a situation or if you don't want to change everything immediately.

No, when dealing with legacy code the issue of syntax is a minor one.

There really should be a very solid reason to
deviate. All the reasons given so far to use (,) in preference to [][]
hold no water IMHO.

(,) is easier to implement and lowers the complication of the code.
There is no need for a special row proxy when you change from the row
major form or to provide safety. It is also miles better than the most
common implementation of [][] though not a whole deal greater than the
best...it's just less complex and therefore the better alternative. IE
keep it as simple as you can but no simpler.

More to the point. You shouldn't be implementing a "2d array". You
should be looking for a better abstraction. Once you have that better
abstraction there is no need, nor desire, to advertize that it is a 2d
array. I think the fact that there is no 2d array in the standard, nor
does there seem to be one comming in the forseable future, is quite
telling.

Your insistance on implementing a basic function as a complex set of
operator overloads reminds me of the subscript operator implemented in
some of the legacy code I work on. Implemented [] for a list that
returns the object with the serial id supplied...it's of course linear.
Then base mass "legacy" code on it in a bunch of for loops. Took me
about 4 hours to pull that member out and change all the [] calls to
functional equivilants. Time well spent IMHO...bad design is bad
design and we shouldn't stick to it just in the name of "legacy" unless
we absolutely have to.

At any rate, like I said...unless you are in the situation of dealing
with legacy code there is no need to worry about it. So why go to all
the trouble of forcing the [][] issue? When you are in the situation
of worrying about legacy code it's a mater of economics...I will grant
that there are probably times when forcing [][] will be the less costly
alternative but it is quite easy to implement as f(,) and then wrap
[][] on top and call it deprecated...in fact it's the easiest and
safest way to implement [][] anyway.
 
S

Simon G Best

Gianni said:
It's time to change the FAQ 13.10/13.11/13.12

I'm inclined to agree that it could do with a rewrite, but I'm not in
favour of going to the opposite extreme of being opposed to using (,).

For 13.10, I think a better answer would be that there are various ways
of doing it:-

* Using operator(), so that all the subscripts can be given in one go.
This, of course, is already illustrated in that FAQ.

* Using operator[], but having it return a proxy as described in a
subsequent FAQ.

* Using member functions, such as row() and col(), to make it explicit
(and therefore clear what's being done). This should also be explained
in a subsequent FAQ.

It should also be emphasized that these aren't mutually exclusive
alternatives, and can all be provided in the same interface. It should,
of course, also be emphasized that the interface should not expose the
implementation.

I'd do away with 13.11, as it is misleading (for reasons disclosed in
this thread). Instead, I'd have 13.12 as the answer to the question,
"Okay, but how do I do it with operator[], then?" I think 13.12 could
do with a bit of rewriting anyway. It could also point out that the
proxy technique can also be used to allow whole columns, as well as
whole rows, to be accessed. That could also serve as a good example of
one of the advantages of keeping the interface independent of
implementation details.

Anyway, those are my quick thoughts on the matter.

Simon
 
N

Noah Roberts

Gianni said:
3. Legacy code can make use of modern templates using the [][] syntax
while converting legacy code to (,) would need major code surgery.

I'd call it rather minor surgery. Any time there is a call to [][]
change to (,)...it's easy.
4. array2D[a] is syntactic sugar for a row reference and can be used to
optimize accesses.

Syntatic sugar yes....optimize accesses? How? Frankly it's no
different at all....assuming the compiler is able to do some basic, and
some less basic, optimizations.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,997
Messages
2,570,240
Members
46,828
Latest member
LauraCastr

Latest Threads

Top