Two-Dimensional Dynamic Arrays

R

roberts.noah

Axter said:
I've been programming for almost 20 years, and I'm 2nd ranking C++
expert in the Experts-Exchange
(http://www.experts-exchange.com/Cplusplus)
I'm also a frequent contributor to Code-Guru C++/VC++ topic area as
well as Code Project Visual C++ and STL topic area.
If this is what you consider a newbie, then I guess I'm a newbie.

Well, I don't really pay attention to "credentials". I've been
published too. BFD. My analysis of your class stands. If you could
counter that analysis I guess you would have. Appeal to authority
isn't good enough in my book.
What ever label you choose to give me or others, does not take away
from the fact that you're argument is flawed and very incorrect.
It's been my experience that debaters that result in name calling do
so, because they don't have a legitimate argument to put forth.

I believe this is the case here.
You've only attempted to side track the real issue with petty
critiques that have nothing to do with the main point.

They actually have everything to do with the main point. Your class
design is fundamentally flawed. You offered it as an example of how to
implement [][] and the plain fact is that your implementation is broken
in ways that are very fundamental and very basic. Your attempt at
creating the [][] syntax just to have that syntax led you down a path
that resulted in code that had fundamental flaws in it destined to
create problems in any decently sized project; my analysis (or
critique) of these things speak directly to the issue. I have
explained those ways already and you fail to answer to them but instead
have decided to claim I sidetracked the issue.

Maybe my claim that you're a newbie was a little unwaranted but the
class you provided as an example of how to do something right as a
counter to the FAQ entry is very newbieish and flawed.
 
R

roberts.noah

Gianni said:
(x,y) does not work with legacy code or generic programming. This is a
major issue if you're looking for a general solution.

I can pretty much answer your entire post right here as this is the
main point. I have already stated that legacy code is an issue. There
is no nice way to deal with code that needs [][] especially if it was
written with C style arrays in mind. Your template classes look nice
but I believe your use of [][] was a mistake.

Now, I have already stated that legacy code or orders from on high are
one thing, but designing a mistake like this in from scratch is a big
mistake. Your template class works great and is rather efficient for C
style array and with vectors of vectors. A C function will still of
course not be able to deal with vectors of vectors so if you have to
use one you are already up shit creek.

But lets look at it from a fresh view kind of standpoint. Being as we
can set asside the issue of legacy code that depends on C style arrays
we can evaluate each implementation's merrit without artificial
requirements. When we are designing from scratch we want robust code
that is also fast. Robust in that it verifys inputs and makes sure
that clients don't try to do something they shouldn't (the argument for
robust code is pretty well known and accepted so I won't go there). We
want fast in both development and testing time as well as run time;
this means we want to do as little as possible to get the job done.

We can create our general functions with the [][] syntax or () syntax -
or with a standard function for that matter. C arrays are obviously
better suited for the [][] syntax so it might seem like the best
choice. However, objects appear to be better suited for the () syntax
for reasons that have already been gone over several times -> The only
protected way to provide [][] in an object is to create an adapter for
the () or function call interface; we can create a simpler
implementation but we expose the internals of the class and basically
ruin the whole purpose of a class so that our array would be better
just exposed and used normally (the only reasons to create an object
class is because of the protections such constructs offer - otherwise
simple functions and PODs are much better).

So, someone already showed us some basics of what would be needed to
implement the () to [][] adapter for an object and still let the class
construct do its job; it was comparitively involved and it wasn't even
finished. So, how would you make an adapter for the other method? I
myself might provide something as simple as:

template<typename T>
class CArrAdapter
{
T * data;
int col_num;
int row_num;
public:
CArrAdapter(T * d, int c, int r) : data(d), col_num(c), row_num(r) {}
T operator () (int i, int j) { if ( i > row_num || j > col_num) throw
something; return *(data + i * col_num + j); }
};

That to me looks a lot simpler, smaller, easier to test and validate,
and just all around better than the adapter required to change () into
[][].

The question now comes of "legacy" code. First off it seems rather
established that we are talking about something similar to the template
classes you posted and not something in C. The reason is simple - you
can't pass a C++ object into a C function that expects an array anyway
- no way to do it (well some very platform specific stuff might work
but lets stay simple).

The thing I like to do with "legacy" code is replace it. Not
immediately of course as time is an issue usually but as things go by I
like to fix little problems I see and eventually totally replace all
"legacy" code with something better - if necissary. So, do we want to
be stuck forever with the [][] syntax or would we eventually like to
replace it with something that is simpler but still robust? This is
when that nice () to [][] adapter comes into play nicely. Use it when
I have to, write everything new with the "better" design, and
eventually the "legacy" code and the adapter go the way of the dodo -
that includes things like those templates you posted though just going
through and changing them might be enough. This is why I feel the
"legacy" code argument is rather weak - I don't like keeping legacy
code if I don't like it and can think of something better...especially
if it gets rid of a lot of nastyness like the breaking of class
boundaries. I especially don't like to stick my design to it.

Now, you also made the claim more recently that you original code post
was not meant to be a *good* example but just a quicky. That is
reasonable, but I for one took it as your real advice and I think the
OP did as well. So then I am gathering that you see the flaw in
returning &vect and agree that it is a problem.

At this point it is assumed that an adapter must be created either
for the object or for the array. I can't think of a decent alternative
and the only alternative offered is fundamentally flawed - you yourself
seem to now be sharing this view as you are now saying your code was
just a "quicky". So, since an adapter is required I say that the
choice is then based on which is the simpler. I would also have the
goal in mind to phaze out the use of C arrays and replace them with C++
objects eventually. My choice at that point is a given.

Now you have my logic on the matter. Either you understand or you
don't. Either you agree or you don't. I don't have any more time to
discuss this right now...the weekend is over.
 
A

Axter

Gianni said:
(x,y) does not work with legacy code or generic programming. This is a
major issue if you're looking for a general solution.

I can pretty much answer your entire post right here as this is the
main point. I have already stated that legacy code is an issue. There
is no nice way to deal with code that needs [][] especially if it was
written with C style arrays in mind. Your template classes look nice
but I believe your use of [][] was a mistake.

Now, I have already stated that legacy code or orders from on high are
one thing, but designing a mistake like this in from scratch is a big
mistake. Your template class works great and is rather efficient for C
style array and with vectors of vectors. A C function will still of
course not be able to deal with vectors of vectors so if you have to
use one you are already up shit creek.

But lets look at it from a fresh view kind of standpoint. Being as we
can set asside the issue of legacy code that depends on C style arrays
we can evaluate each implementation's merrit without artificial
requirements.

That is not an artificial requirement, and any experience programmer
would tell you that.
Legacy code is a very real world, and very common requirement for day
to day coding.
Often when adding new modifications to legacy code, you're force to use
the current interface, which would exclude using operator().
It would be a terrible idea to introduce the use of operator() in one
part of the source code, and use [][], in another part of the same
source code.
And changing the entire code to use operator() would more then likely
introduce many bugs, that wouldn't get picked up until your customer
reports it.
It's an equally bad idea to say it's better to use raw pointers, which
would also have a high chance of introducing new bugs.
It's safer to use a wrapper class, like the one I posted.

The main purpose for the wrapper class is to show how to efficiently
implement a dynamic 2D array class using [][] interface.
I intentionally did not add any extra bounds checking code, because
that would have created a distraction from the main implementation I
was trying to convey.
Any beginner can add GetX and GetY functions to this class:
int GetRow() const{return m_row;}
int GetCol() const{return m_col;}

If you don't know how to do this, then you shouldn't even be looking at
this class.
http://code.axter.com/dynamic_2d_array.h

When we are designing from scratch we want robust code
that is also fast. Robust in that it verifys inputs and makes sure
that clients don't try to do something they shouldn't (the argument for
robust code is pretty well known and accepted so I won't go there). We
want fast in both development and testing time as well as run time;
this means we want to do as little as possible to get the job done.

We can create our general functions with the [][] syntax or () syntax -
or with a standard function for that matter. C arrays are obviously
better suited for the [][] syntax so it might seem like the best
choice. However, objects appear to be better suited for the () syntax
for reasons that have already been gone over several times ->
I completely disagree. I've only read contrived justifications for
using () syntax, that have nothing to do with generic programming, or
with 99.99% of C++ development.
Example:
Previous Post:
Tell me then, how exactly is the compiler going to hide the internal representiation of
the matrix when you have exposed it with the first [] operator??!!

99.99% of developers would never ever need to get the internal
representation of the matrix, and would never need to change col for
row within the matrix.
For those very few developers that do need to perform such optimization
methods, most likely their implementation will only work efficiently in
a particular OS and hardware settings.
It would not be generic implementation, that you could port to other OS
or even other hardware using the same OS.
A developer would have a better chance of winning the lottery, then
ever having to use these optimization methods.

The justification given in the C++ FAQ and the justification given in
this thread, are very weak at best, and play no part in generic C++
programming.
protected way to provide [][] in an object is to create an adapter for
the () or function call interface; we can create a simpler
implementation but we expose the internals of the class and basically
ruin the whole purpose of a class so that our array would be better
just exposed and used normally (the only reasons to create an object
class is because of the protections such constructs offer - otherwise
simple functions and PODs are much better).

There are many, many reasons to create an object class, and protection
is only one of many.
The dynamic_2d_array class is type safe, and reduces the chance of
memory leaks compare to using pointers.
Other then using pointers, you can not create a dynamic 2D array using
POD concrete types.
It's far safer to use the wrapper class.
So, someone already showed us some basics of what would be needed to
implement the () to [][] adapter for an object and still let the class
construct do its job; it was comparitively involved and it wasn't even
finished. So, how would you make an adapter for the other method? I
myself might provide something as simple as:

template<typename T>
class CArrAdapter
{
T * data;
int col_num;
int row_num;
public:
CArrAdapter(T * d, int c, int r) : data(d), col_num(c), row_num(r) {}
T operator () (int i, int j) { if ( i > row_num || j > col_num) throw
something; return *(data + i * col_num + j); }
};

That to me looks a lot simpler, smaller, easier to test and validate,
and just all around better than the adapter required to change () into
[][].
There are so many things wrong with the above class.
1. The above class is not safe as it can be since col_num and row_num
are not constant. Clearly they should be constant, since there's no
implementation for changing the size of the array.

2. Your class can not be used if the object is constant, since you
failed to provide a constant version for operator().

3. Your implementation is returning by value, which makes it very
inefficient.

4. The class also fails to test that the input pointer is not NULL.
(should have assertion).

5. Since your class is taking int instead of size_t, your class can
also fail if the input arguments are negative. CArrAdapter
MyBadArrAdapter(NULL, -3, -99);

6. MyBadArrAdapter(-4, -123);//Your if condition would not pick this
up, and would not throw

7. I also find very little value in this class, since it does not do
any clean up work, and therefore you would most likely end up with
memory leaks. It would be just as bad as using raw pointers.

Anyone using this type of class in a real world requirement, would end
up with memory leaks, poor performance, and a maintenance nightmare.
 
G

Gianni Mariani

Gianni Mariani wrote:

(x,y) does not work with legacy code or generic programming. This is a
major issue if you're looking for a general solution.


I can pretty much answer your entire post right here as this is the
main point. I have already stated that legacy code is an issue. There
is no nice way to deal with code that needs [][] especially if it was
written with C style arrays in mind. Your template classes look nice
but I believe your use of [][] was a mistake.

Stop.

You have 2 options, a) makes for hard work, b) means less work. The
result is identical from a performance prespective. You insist on
option a).

Enough said.
 
A

Axter

Gianni said:
(x,y) does not work with legacy code or generic programming. This is a
major issue if you're looking for a general solution.

I can pretty much answer your entire post right here as this is the
main point. I have already stated that legacy code is an issue. There
is no nice way to deal with code that needs [][] especially if it was
written with C style arrays in mind. Your template classes look nice
but I believe your use of [][] was a mistake.

Now, I have already stated that legacy code or orders from on high are
one thing, but designing a mistake like this in from scratch is a big
mistake. Your template class works great and is rather efficient for C
style array and with vectors of vectors. A C function will still of
course not be able to deal with vectors of vectors so if you have to
use one you are already up shit creek.

But lets look at it from a fresh view kind of standpoint. Being as we
can set asside the issue of legacy code that depends on C style arrays
we can evaluate each implementation's merrit without artificial
requirements. When we are designing from scratch we want robust code
that is also fast. Robust in that it verifys inputs and makes sure
that clients don't try to do something they shouldn't (the argument for
robust code is pretty well known and accepted so I won't go there). We
want fast in both development and testing time as well as run time;
this means we want to do as little as possible to get the job done.

We can create our general functions with the [][] syntax or () syntax -
or with a standard function for that matter. C arrays are obviously
better suited for the [][] syntax so it might seem like the best
choice. However, objects appear to be better suited for the () syntax
for reasons that have already been gone over several times -> The only
protected way to provide [][] in an object is to create an adapter for
the () or function call interface; we can create a simpler
implementation but we expose the internals of the class and basically
ruin the whole purpose of a class so that our array would be better
just exposed and used normally (the only reasons to create an object
class is because of the protections such constructs offer - otherwise
simple functions and PODs are much better).

So, someone already showed us some basics of what would be needed to
implement the () to [][] adapter for an object and still let the class
construct do its job; it was comparitively involved and it wasn't even
finished. So, how would you make an adapter for the other method? I
myself might provide something as simple as:

template<typename T>
class CArrAdapter
{
T * data;
int col_num;
int row_num;
public:
CArrAdapter(T * d, int c, int r) : data(d), col_num(c), row_num(r) {}
T operator () (int i, int j) { if ( i > row_num || j > col_num) throw
something; return *(data + i * col_num + j); }
};

That to me looks a lot simpler, smaller, easier to test and validate,
and just all around better than the adapter required to change () into
[][].

I forgot to mention that your wrapper class also fails to have a GetCol
and GetRow function.

For better advise on this subject, check out the following CodeGuru STL
FAQs:
http://www.codeguru.com/forum/showthread.php?t=231046

The above STL FAQ has a wrapper class for a 2D array, which uses
vector<vector<T> >.
It has a resize function that allows the size to change after object
construction.
It would be safer to use this type of implementation, and it would be
eaiser to interface your code with STL objects.

The CodeGuru FAQ author also originally promoted the operator() method,
and after much debate, he changed the FAQ to promote [][] instead.

The CodeGuru site is a well known respected site, that has members that
are much better at responding to critiques then the author of the C++
FAQ.

Also check out another CodeGuru STL FAQ:
http://www.codeguru.com/forum/showthread.php?s=&threadid=297838

The above link has two classes. One which I'm the author of, and the
second class which allows you to use both [][] and operator() method.
I don't think it's a good idea to have both methods in a class, but
some developers may find this method more acceptable.
 
G

Gianni Mariani

Axter wrote:
....
The above link has two classes. One which I'm the author of, and the
second class which allows you to use both [][] and operator() method.
I don't think it's a good idea to have both methods in a class, but
some developers may find this method more acceptable.

I thought about putting both () and [][] in a class and I came to the
conclusion that you don't want to encourage both methods. You really
only want one, if someone is desperate for a (x,y) method, they can
easily add one.
 
G

Gianni Mariani

jrp said:
Are there any additional issues with extending this code to THREE
dimensions?

For dynamically sized matrix classes of three or more dimensions, if you
want to use a [][][] syntax, you need to use a proxy object as a result
of the first operator[] calls > 2.
 
R

roberts.noah

Axter wrote:
However, objects appear to be better suited for the () syntax
for reasons that have already been gone over several times ->
I completely disagree. I've only read contrived justifications for
using () syntax, that have nothing to do with generic programming, or
with 99.99% of C++ development.
Example:
Previous Post:
Tell me then, how exactly is the compiler going to hide the internal representiation of
the matrix when you have exposed it with the first [] operator??!!

99.99% of developers would never ever need to get the internal
representation of the matrix, and would never need to change col for
row within the matrix.

Uh...the problem I have cited over and over and over again with all but
one implementation of the operator[][] method of matrix/2d array has
been that the internal rep is already exposed; there are a hundred
things wrong with this and I have reiterated some of these several
times. I don't know why you bring up the point that 99.99% of
developers don't need to access the internals of the matrix class...I
would make this a stronger point and say that 100% of developers do not
need to access the internals of a matrix class. Those that need more
performance than they can get through the interface should use a
different class or maybe they even need to use C arrays period and toss
out all the "OO Overhead".

You keep running around in circles missing the point completely. Now
you are just talking nonsense - well the statement you made makes
sense, just not in the context of the argument and certainly not
*against* anything I have said, in fact it only reinforces my points.
 
R

roberts.noah

Gianni said:
jrp said:
Are there any additional issues with extending this code to THREE
dimensions?

For dynamically sized matrix classes of three or more dimensions, if you
want to use a [][][] syntax, you need to use a proxy object as a result
of the first operator[] calls > 2.

Why not just return &&array[x]

Notice how the () syntax keeps encapsulation without the need of an
adapter even with 2d and with 3d still doesn't need one.
 
G

Gianni Mariani

Why not just return &&array[x]

Notice how the () syntax keeps encapsulation without the need of an
adapter even with 2d and with 3d still doesn't need one.

plonk
 
R

roberts.noah

Axter said:
I forgot to mention that your wrapper class also fails to have a GetCol
and GetRow function.

You are of course right and that is an obvious problem except for one
thing. The presented class is an adapter to provide () syntax when
using a C array. Since someone that needs that adapter is already
using a C array outside of a class and so is tracking the dimensions
already the GetCol and GetRow functions would be redundant. However,
since the addition of these functions is relatively straight forward
and could come of use, possibly, their ommision is probably a mistake.

As you also state, I could have also improved it to also adapt vectors.
Also check out another CodeGuru STL FAQ:
http://www.codeguru.com/forum/showthread.php?s=&threadid=297838

The above link has two classes. One which I'm the author of, and the
second class which allows you to use both [][] and operator() method.
I don't think it's a good idea to have both methods in a class, but
some developers may find this method more acceptable.

Decent:
http://www.codeguru.com/forum/showthread.php?s=&threadid=231046

Still has a dependency that could be removed. It could be more
abstract. No matter how you slice it the interface still spells out a
particular alignment. This is forgivable but with op() that problem
doesn't exist so that is still +1 for op().

The reason this version is better is that because it returns a vector
reference instead of pointer to a memory chunk; therefor the class is
protected from clients trying to overwrite into a second row on
accident. The vector interface is sufficient to offer protection in
this area and it still retains a great deal of efficiency. Basically
the vector is acting a lot like the previously supplied "proxy".

On the other hand, this class doesn't seem that necessary. Why not
just use the vector<vector<> > in the open? The only really nice thing
this class offers is the sizing of the internal vectors. Makes me
wonder if the constructor shouldn't just call resize.

The other link you have above... The first class is no good; it is the
same trash you already posted in fact - why are you wasting everyone's
time like that? Do you think that by looking at it somewhere else it
will change the problems inherent in its design??

Second implementation also has problems but is several degrees better
than yours. I would remove the op[]'s. The iterator idea was great
but could have been expanded to include columns. getRow is dangerous
and has the same problems as op[] - I think it would be better to stay
with the iterator idea and toss getRow or just make it return an
iterator.
 
R

roberts.noah


Come to think of it, I like it less now that I think on it....not for a
real 2d matrix anyway - or anything where rows should be the same
length. Reason is simple:

T t();

mtx[x].push_back(t);

This is ok, since the class doesn't stop you from doing it (and can't)
but it's rather ugly. The purpose of this class seems pretty straight
forward in that the above call shouldn't be allowable even though it
is. This is a pretty tricky problem though and I'm not surprised it
slipped past the developer (maybe it didn't and they decided to live
with it). The answer is of course that some sort of policy is created
that is self enforced by developers...someone usually breaks that kind
of policy though. Any client that used the iterator interface or based
its operation on .size() could break down with the above, buggered mtx.

It's a point against it anyway. You can do the same with
vector<vector<> > but at least that isn't pretending to be rectangular.
The single chunk of memory solution also seems to have the possibility
at least of being more efficient....less redirections.

Of course this is also caused by an encapsulation issue. I tricked
myself into thinking it would be ok in this case. Just goes to show I
guess.

You could fix this by returning a class that *contains* the vector (or
non-public inheritance) that did not provide the functions that would
pose the problem. This works because it fixes the encapsulation issue.
If you thought ahead enough this returned class could be based on
something abstract that could be implemented in any number of
manners...meaning the vectors wouldn't even have to be there at all.

In the end it is similar to the previous example and I still think the
() interface still ends up providing the same benefits with less work.
 
J

jrp

I can see both sides of the argument so far, but would like to explore
a bit further real world usage and performance of such classes,
including with"legacy" code.

The first thing that most of the above examples would need is const
versions of many of the operations; the second is that it needs to be
possible to use an aligned malloc to allocate storage to get the
benfits of vectorization. Finally, it needs to be possible to allocate
the memory so that there is no aliasing (or do so via a restrict
decoration).

To be more specifif, suppose that I want to build a system of 3d
numeric objects (cubes) that can be sliced into 2 and 1d objects
(planes, rows), and those 2d objects can also be sliced into 1d rows.
And I want to be able to present those rows to legacy C routines that
expect C arrays and lengths. I also want to be able to do things like

acube = 0;
acube[nplane] = 0;

aplane[nrow] =0;

acube[nplane] = aplane;

and present an acube[nplane] to a routine as a const Plane& parameter.

(using () if necessary).

As I understand it, the original intention was for valarray + slice to
do this job but that seems to be harder to achieve efficiently and
usable.

There are those that say use Blitz++, or boost::multi_array, or
stlorg::fixed_array. These are heavy packages, yet none of them seems
to provide a drop-in replacement for the ugly but functional
vector<vector<vector>>> and [][][].


It would be helpful to discuss this on the basis of some concrete
candidate classes such as those earlier in the thread so that we can
test performance / applicability. For example, are address
dereferences slower than int multiplications?
 
A

Axter


Come to think of it, I like it less now that I think on it....not for a
real 2d matrix anyway - or anything where rows should be the same
length. Reason is simple:

T t();

mtx[x].push_back(t);

This is ok, since the class doesn't stop you from doing it (and can't)
but it's rather ugly. The purpose of this class seems pretty straight
forward in that the above call shouldn't be allowable even though it
is. This is a pretty tricky problem though and I'm not surprised it
slipped past the developer (maybe it didn't and they decided to live
with it). The answer is of course that some sort of policy is created
that is self enforced by developers...someone usually breaks that kind
of policy though. Any client that used the iterator interface or based
its operation on .size() could break down with the above, buggered mtx.

It's a point against it anyway. You can do the same with
vector<vector<> > but at least that isn't pretending to be rectangular.
The single chunk of memory solution also seems to have the possibility
at least of being more efficient....less redirections.

Of course this is also caused by an encapsulation issue. I tricked
myself into thinking it would be ok in this case. Just goes to show I
guess.

You could fix this by returning a class that *contains* the vector (or
non-public inheritance) that did not provide the functions that would
pose the problem. This works because it fixes the encapsulation issue.
If you thought ahead enough this returned class could be based on
something abstract that could be implemented in any number of
manners...meaning the vectors wouldn't even have to be there at all.

In the end it is similar to the previous example and I still think the
() interface still ends up providing the same benefits with less work.

I know you among others, don't seem to see a syntax problem with using
operator(), but here's a small example of how using operator() instead
of [][] can make your code ambiguous.
CMatrix arr(12, 34);
..... lost of other code ....
..... losts more code ....
int x = arr(1, 3);// Is arr a function, or a class????

If arr is far removed from it's declaration, a normal assumption would
be to think arr is a function, and the above line of code is calling a
global arr function.

int x = arr[1][3]; // This is much less ambiguous, and easy to identify
arr as an array

Using operator() for arrays makes the code more confusing, and harder
to read and maintain, where as using [][] is straight forward, and very
easy to pick what's going on in above line of code.
Why use ambiguous syntax when you don't have to?????
 
K

Kai-Uwe Bux

Axter said:
[snip]
I know you among others, don't seem to see a syntax problem with using
operator(), but here's a small example of how using operator() instead
of [][] can make your code ambiguous.
CMatrix arr(12, 34);
.... lost of other code ....
.... losts more code ....
int x = arr(1, 3);// Is arr a function, or a class????

If arr is far removed from it's declaration, a normal assumption would
be to think arr is a function, and the above line of code is calling a
global arr function.

int x = arr[1][3]; // This is much less ambiguous, and easy to identify
arr as an array

Using operator() for arrays makes the code more confusing, and harder
to read and maintain, where as using [][] is straight forward, and very
easy to pick what's going on in above line of code.
Why use ambiguous syntax when you don't have to?????

To me, it seems that the problem in this code does not arise from
overloading operator(). It arises from choosing a poor variable name. C++
has the feature of allowing for function objects. Therefore, any expression
like

identifier( arg_1, arg_2, arg_3 );

could be a function call, creation of a temporary, invoking operator(), or
maybe even more. The way to cope with this "ambiguity" is not to ban
overloading operator() but to choose identifiers wisely so that an object
of type CMatrix can be recognized as such.


Best

Kai-Uwe Bux
 
A

Axter

Kai-Uwe Bux said:
Axter said:
[snip]
I know you among others, don't seem to see a syntax problem with using
operator(), but here's a small example of how using operator() instead
of [][] can make your code ambiguous.
CMatrix arr(12, 34);
.... lost of other code ....
.... losts more code ....
int x = arr(1, 3);// Is arr a function, or a class????

If arr is far removed from it's declaration, a normal assumption would
be to think arr is a function, and the above line of code is calling a
global arr function.

int x = arr[1][3]; // This is much less ambiguous, and easy to identify
arr as an array

Using operator() for arrays makes the code more confusing, and harder
to read and maintain, where as using [][] is straight forward, and very
easy to pick what's going on in above line of code.
Why use ambiguous syntax when you don't have to?????

To me, it seems that the problem in this code does not arise from
overloading operator(). It arises from choosing a poor variable name. C++
has the feature of allowing for function objects. Therefore, any expression
like

I agree, but you find too many developers that will use short
initialized names, that may be perfectly clear to them, but complete
ambiguous to the next developer that has to maintain his/her code.
I'm not advocating a ban on using operator(). I just don't think using
it in place of [][] is appropriate, and leads to ambiguous code.
 
R

roberts.noah

jrp said:
To be more specifif, suppose that I want to build a system of 3d
numeric objects (cubes) that can be sliced into 2 and 1d objects
(planes, rows), and those 2d objects can also be sliced into 1d rows.
And I want to be able to present those rows to legacy C routines that
expect C arrays and lengths. I also want to be able to do things like

acube = 0;
acube[nplane] = 0;

I take it that the above is filling with 0's? I see the need for such
an operation but I am not sure I like the syntax. You could also be
meaning (especially in the top instance) assign to this cube with a
cube with no dimensions.
aplane[nrow] =0;

acube[nplane] = aplane;

I can also see the need for this operation but I think the syntax is
flawed here as well. Do you mean X, Y, or Z axis plane? Functional
syntax would be better here I think. Could be a single function
getPlane(x, axis) or three seperate for each axis.
and present an acube[nplane] to a routine as a const Plane& parameter.

Or even a non const. Seems you would also want to be able to pass
planes, rows, or individual items to manipulators.
It would be helpful to discuss this on the basis of some concrete
candidate classes such as those earlier in the thread so that we can
test performance / applicability. For example, are address
dereferences slower than int multiplications?

I would add a requirement. You must be able to create a new class that
stores its data in a different manner, possibly col mjr form but could
be anything, that will work as a parameter to any function or algorithm
that expects the designed class.

I'll play but it will take a while as time is an issue.
 
J

jrp

Thanks. I won't quibble about the syntax (although there is a logic to
it). What interests me is ((empirical) relative performance, including
vectorizability) and completeness: so missing const versions of
operators are an issue, and may help to tip the balance for those
interested in clutter / complexity.
I'll play but it will take a while as time is an issue.

Thanks. Likewise. Happy to contribute, if necessary.
 

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,239
Members
46,827
Latest member
DMUK_Beginner

Latest Threads

Top