Two-Dimensional Dynamic Arrays

K

Kai-Uwe Bux

Gianni said:
Gianni Mariani wrote: [snip]
Otherwise I declare the FAQ


That is of course your own perogative.

Thank you.
A smarter person, however,
might decide to learn from it. I really doubt you actually read that
FAQ and comprehended what it was saying because the things you are
saying don't leave much doubt.

You like walking on thin ice ?


Here is the same matrix code I posted earlier now using a proxy class as
I described. Now what do you have to say about the FAQ ?
[code snipped]

That it covers the proxy class approach in 13.12; that it agrees with your
assment about optimization of the proxy temporary; and that it discusses
the valid reasons you put forward as to when and why you might want to use
it. BTW, it also contains a reminder not to forget about const versions of
the required operators.

You still think it's hogwash?


Best

Kai-Uwe Bux
 
G

Gianni Mariani

Gianni said:
It's quite easy to turn [A] into (A,B) with no loss of performance
(on a good optimizing compiler).


Oh really??!! 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??!! How is the compiler going to decide to
use column major instead of row major, or visa-versa, when it is the
better way to represent the matrix for the particular needs, when you
have created a dependency on row major by using the [] operator to
return rows??!!


Using a proxy class.
As the FAQ says, there is never a time when () is worst than [][].

"()" won't work on legacy code, "[][]" will. "[][]" lets me use
templates that work with regular matricies and my special matrix class
as well.
What exactly do you think the diff is between [] and () that would make
you think the compiler would get more confused over one vs. the other?

That's a silly question. It all depends on how you implement [] and ().
Give me an example where [A] is slower than (A,B) (using an decent
optimizer) and we'll see if we can fix it.



Go back and read the FAQ - it gives just such an example.


That's not an example, I need to see results based on real compilers in
real live code. Without it, this dicussion is like pissing into a
hurricane.

Also keep
the definition of the word, "encapsulation," in mind as you read it and
try to realize what you have done by tossing out &vector[x] to
artificially create [x][y]. I mean, why even offer the protection of
the class boundary if you are going to bypass it like that??!!

The proxy class gives you encapsulation (if you need it).
Hint: not only have you created a dependency on the internals of your
own class in a rather icky way you have created a dependency on how the
std::vector class is implemented. It is highly unlikely to be
implemented in any other way but the standard does not guarantee that
behavior.

I think you're mistaken. std::vector is quite well defined, objects are
contiguous.
Point is that dependencies now exist that never should exist
in a well structured program; these are the things that create code rot
right off the bat.

If this is a problem, you can break that dependantcy, even using [][].
Otherwise I declare the FAQ



That is of course your own perogative.

Thank you.
A smarter person, however,
might decide to learn from it. I really doubt you actually read that
FAQ and comprehended what it was saying because the things you are
saying don't leave much doubt.

You like walking on thin ice ?


Here is the same matrix code I posted earlier now using a proxy class as
I described. Now what do you have to say about the FAQ ?

#include <vector>

template <typename w_elem_type>
class matrix
{
public:
typedef int t_Size;

t_Size m_columns;
t_Size m_rows;

std::vector<w_elem_type> m_data;

matrix( t_Size i_columns = 0, t_Size i_rows = 0 )
: m_columns( i_columns ),
m_rows( i_rows ),
m_data( i_columns * i_rows )
{
}

class proxy
{
friend class matrix;

matrix & m_matrix;
t_Size m_row;

proxy(
matrix & i_matrix,
t_Size i_row
)
: m_matrix( i_matrix ),
m_row( i_row )
{
}

public:
w_elem_type & operator[]( t_Size i_column )
{
return m_matrix.m_data[
i_column + m_matrix.m_columns * m_row
];
}

private:
proxy( const proxy & );
proxy & operator=( const proxy & );
};

proxy operator[]( t_Size i_row )
{
return proxy( * this, i_row );
}

template <typename w_Type, int w_rows, int w_columns>
matrix( const w_Type (&i_array)[w_rows][w_columns] )
: m_columns( w_columns ),
m_rows( w_rows ),
m_data(
& (i_array[0][0]),
w_columns * w_rows + & (i_array[0][0])
)
{
}

};



#include <iostream>

double array[3][4] = {
{ 1.0, 2.0, 3.3, 4.4 },
{ 1.0, 2.0, 3.3, 4.4 },
{ 1.0, 2.0, 3.3, 4.5 },
};

int main()
{
matrix<float> mat1( 3, 4 );
matrix<float> mat2;
matrix<float> mat3( array );

mat2 = mat3;

std::cout << mat2[2][3] << "\n";
}

// note: I fixed a row/column transpose issue
 
A

Axter

Gianni said:
Gianni said:
It's quite easy to turn [A] into (A,B) with no loss of performance
(on a good optimizing compiler).


Oh really??!! 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??!! How is the compiler going to decide to
use column major instead of row major, or visa-versa, when it is the
better way to represent the matrix for the particular needs, when you
have created a dependency on row major by using the [] operator to
return rows??!!


Using a proxy class.
As the FAQ says, there is never a time when () is worst than [][].


IMHO, the justification for using () instead of [][] is very poor.
The scenario in which you can take advantage of the use of operator()
is one in which very very few developers would ever come across.
It's my opinion that the author of the FAQ is has had more experience
with these of the wall scenario, and is in the mistaken impression,
that others would ever need this type of requirement.

I recommend using [][] over operator(), because it's easier to read,
and to maintain.
It's also easier to port back and forth with standard C-Style 2D
arrays.

See following link for efficient implementation:
http://code.axter.com/dynamic_2d_array.h

Or check out code guru for a vector version.
 
G

Gianni Mariani

Kai-Uwe Bux said:
(e-mail address removed) wrote: ....

The FAQ makes the claim that the [][] interface is less flexible. This is
*not* true in general. The FAQ somehow seems to assume that the only way of
realizing the [][] interface is that operator[] returns an array or
something similar that exposes the internal representation of the matrix
class.


As is done in the above code.

However, you do not need to expose the internal representation at .... snipped proxy example ...
}; // matrix


That is an aweful lot of work just to get a particular syntax that just
ends up using the equivilant of (x,y).

Exactly what is your issue ? The quantity of code ? If it's code
quantity, I suspect that some people will end up with more code with the
"(,)" implementation since they can't any matrix templates that use the
"[][]" syntax.

The grand-parent poster showed that the evaluation of "[][]" can be done
at exactly the same level as "(,)", which means that they are EQUAL from
a language flexibility point of view.
Note that in expressions like A[row][col], the proxy should be optimized
away be a moderately smart optimizing compiler.


Are you sure? Have you tested this theory of yours with your own
compiler?

I have, but only when it became an issue. In the example I posted
elsewhere, the gcc compiler will issue the exact same code for (,) and
[][] at "O1" level optimization. (gcc 4.0.0) The same goes for MSVC7.1.
I think you are expecting rather a lot from your compiler if
you expect that it will actually optimize out objects you tell it to
create; even more if you expect all compilers to do so. You could be
right but honestly that seems like a lot to expect, especially when the
alternative answer (different syntax, no proxy) is much more easily
optimized away and is already much more optimized than your answer
without any intelligence on behalf of the compiler.

IMO there is a balance that you need to achieve between being overly
agressive with your optimizations and depending on the compiler to do
your work for you. Adding a bunch of unnecissary code and objects to
create a specific syntax and expecting the compiler to just magically
get rid of it all is a little to far into the later area for me.

Does that mean you don't use smart pointers, inlined functions or helper
classes of any kind ?

The FAQ is wrong as it clearly makes a number of false statements.

1. "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."

This statement is claiming an issue with "flexibility" and
"optimization" but it clearly does not give any basis in fact.

2. "For example, the easiest way to implement the [][] ...",

Comparing "the easiest" way for option A and the "best" approach for
option B is comparing apples and oranges.

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

Patently false. If code I have uses "[][]", then quite clearly, using
the "()" approach is significantly worse.

4. "As an example of when a physical layout makes a significant
difference, ..."

This has nothing to do with the "[][]" approach vs the "(,)" approach.
As has been shown, we can easily separate the implementation from the
syntax using a proxy class. The whole paragraph is nonsensical.

5. "it has no down-side and a potential up-side"

Within entire FAQ, it has not given one thing you can do with "(,)" that
you cannot do with "[][]" yet it claims that "(,)" has a potential
upside. I still claim that there exists code that would take longer to
convert to "(,)" and will work with "[][]". I can even implement "[][]"
in tems of "(,)" which means that anything that you can do with "(,)"
can be done with "[][]".
 
G

Gianni Mariani

....
You still think it's hogwash?

Yes, there is no reason to favour "(,)" over "[][]". 13.11 and 13.12
makes this distinction over and over yet provides no basis in fact that
one is superior to the other when in fact they are equivalent. So yes,
IMHO, now that I have looked at the generated code, hogwash it is since
they are 100% the same when it comes to compiled code on the 2 compilers
i tested it on.
 
G

Gianni Mariani

Kai-Uwe Bux wrote:
....
True, but somewhat irrelevant. The FAQ item 13.11 does not specifically talk
about the *above code*. Also, I do not read the claim

Ok - then the FAQ is mileading hogwash at best.
 
K

Kai-Uwe Bux

Gianni said:
...
You still think it's hogwash?

Yes, there is no reason to favour "(,)" over "[][]". 13.11 and 13.12
makes this distinction over and over yet provides no basis in fact that
one is superior to the other when in fact they are equivalent. So yes,
IMHO, now that I have looked at the generated code, hogwash it is since
they are 100% the same when it comes to compiled code on the 2 compilers
i tested it on.

I think you are misreading the FAQ a little. It gives a (valid) reason to go
for () instead of [][]: it is *simpler* to encapsulate the innards of your
matrix class using (). Keep in mind that the FAQ is written with a newbie
reader in mind. If a newbie was to think "how would I implement a matrix
class and realize the [][] interface", the newbie would very likely end up
with code that exposes the internal representation. The FAQ is written to
make the life of this hypothetical newbie easier.

I read the remarks about performance as giving reasons as to why you want to
keep the implementation details hidden -- reasons more specific than the
general philosophical yadda yadda about encapsulation. Now, if you want to
keep encapsulation and provide the [][] interface, you will go for a proxy
class, which is considerably more tricky -- in particular if you want to
provide const versions of the interface, as well. Thus, the () interface is
the "keep it simple" approach to designing a matrix class. In my book, that
is an advantage (and not only for newbies).


Best

Kai-Uwe Bux
 
R

roberts.noah

Kai-Uwe Bux said:
Kai-Uwe Bux said:
(e-mail address removed) wrote:


Gianni Mariani wrote:
(e-mail address removed) wrote:
Gianni Mariani wrote:


w_elem_type * operator[]( t_Size i_index )
{
return & ( m_data[ i_index * m_rows ] );
}


This FAQ entry might be of interest:

http://www.parashift.com/c++-faq-lite/operator-overloading.html#faq-13.11

See also 13.10 right above it.


That FAQ is a classic case of premature optimization.

It's quite easy to turn [A] into (A,B) with no loss of performance
(on a good optimizing compiler).

Oh really??!! 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??!! How is the compiler going to decide to
use column major instead of row major, or visa-versa, when it is the
better way to represent the matrix for the particular needs, when you
have created a dependency on row major by using the [] operator to
return rows??!!

The FAQ makes the claim that the [][] interface is less flexible. This is
*not* true in general. The FAQ somehow seems to assume that the only way
of realizing the [][] interface is that operator[] returns an array or
something similar that exposes the internal representation of the matrix
class.


As is done in the above code.


True, but somewhat irrelevant. The FAQ item 13.11 does not specifically talk
about the *above code*.


Not at all irrelivant as the above is the code being discussed. If you
would like to change subject feel free to do so but don't be surprised
if you find I get bored rather quickly with such tactics.

Also, I do not read the claim
It's quite easy to turn [A] into (A,B) with no loss of performance
(on a good optimizing compiler).


as a claim about the particular implementation given up the thread.


Not a claim made by me and not a claim that made much sense imo.
 
R

roberts.noah

Gianni said:
(e-mail address removed) wrote:

Does that mean you don't use smart pointers, inlined functions or helper
classes of any kind ?

You truely are lost. Go back to school. A -> B therefore C is not
valid logic.
Within entire FAQ, it has not given one thing you can do with "(,)" that
you cannot do with "[][]" yet it claims that "(,)" has a potential
upside. I still claim that there exists code that would take longer to
convert to "(,)" and will work with "[][]". I can even implement "[][]"
in tems of "(,)" which means that anything that you can do with "(,)"
can be done with "[][]".

You are wrong here again and again the point has just gone right past
you without one iota of understanding or even a hint that you realized
it was there. [][] by its definition creates an internal dependency
unless you create some, totally unnecissary to the task, proxy to
artificially impose the syntax paradigm in an abstract manner that in
the end just uses the more appropriate syntax of (x,y).

In other words, and hopefully ones you can understand this time as they
are in the FAQ and have been reiterated several times here, there is no
way to change the form of the matrix storage once you have created [][]
as you have done. You can't then decide that the computer would be
able to compute things faster if the matrix was stored in column major
form because all clients would then, necissarily, have to change! This
is unacceptable; a change to the private internals of a class should
NEVER affect its users. Creating a proxy answers this problem by
returning an object that just stores X and calls (x,y) on the matrix to
return the appropriate value. This is totally unnecissary and only
adds to the complexity of the program without giving any real benefit -
all it does is provide a particular syntax for minds too closed to
realize it is easier, and more efficient, the other way. If there is
some reason why [][] MUST be used (some screwed up 3rd party lib,
orders from on high or whatever) then you better provide it, and a
proxy (or adapter) seems like a good way of doing so, but starting from
scratch and imposing this mistake is a big mistake.

The code you provided to the OP is a perfect example of how NOT to
write good objects as it exposed the internals of not only the class
itself but it also exposed the internals of a class to which you have
no control (std::vector)...and it did so in a manner that left the
class no way to protect its *private* parts from external influence.
This just murders all reason for using objects in the first place.
Everyone does this from time to time but it is the better programmer
that can see that and learn from that mistake. Hopefully the OP is
reading this and understands better than you and can see that you made
a mistake there even if you can't (or are too proud to admit).

[][] doesn't even make sense for anything other than a vector that
contains vectors anyway - one for the vector and one for the vector it
contains at that index. There is no such operator as [][] and imposing
one simply for the sake of imposing one is just silly, pointless, and
harmful. It's rot, pure and simple.
 
K

Kai-Uwe Bux

Kai-Uwe Bux said:
Kai-Uwe Bux wrote:
(e-mail address removed) wrote:


Gianni Mariani wrote:
(e-mail address removed) wrote:
Gianni Mariani wrote:


w_elem_type * operator[]( t_Size i_index )
{
return & ( m_data[ i_index * m_rows ] );
}


This FAQ entry might be of interest:

http://www.parashift.com/c++-faq-lite/operator-overloading.html#faq-13.11

See also 13.10 right above it.


That FAQ is a classic case of premature optimization.

It's quite easy to turn [A] into (A,B) with no loss of
performance (on a good optimizing compiler).

Oh really??!! 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??!! How is the compiler going to decide
to use column major instead of row major, or visa-versa, when it is
the better way to represent the matrix for the particular needs,
when you have created a dependency on row major by using the []
operator to return rows??!!

The FAQ makes the claim that the [][] interface is less flexible. This
is *not* true in general. The FAQ somehow seems to assume that the
only way of realizing the [][] interface is that operator[] returns an
array or something similar that exposes the internal representation of
the matrix class.

As is done in the above code.


True, but somewhat irrelevant. The FAQ item 13.11 does not specifically
talk about the *above code*.


Not at all irrelivant as the above is the code being discussed.


Nope, the discussion actually left that code with the introduction of the
statement:
It's quite easy to turn [A] into (A,B) with no loss of
performance (on a good optimizing compiler).


Ever since this statement, we have been are talking about a different
implementation (at that point in the thread a hypothetical one, but as of
now, we have two drafts) where [][] is reduced to (,). Had you wanted to
return to the old code, you should not have presented your remarks as a
rebuttal to that line since critique of the old code is of no relevance for
the evaluation of this quote.
If you would like to change subject feel free to do so but don't be
surprised if you find I get bored rather quickly with such tactics.

As argued above, you are slightly mistaken about the topic. However, if you
want to discuss an implementation that has been superseeded, feel free.
However, I think that your critique of that code is not really disputed.
Also, I do not read the claim
It's quite easy to turn [A] into (A,B) with no loss of
performance (on a good optimizing compiler).


as a claim about the particular implementation given up the thread.


Not a claim made by me and not a claim that made much sense imo.


The statement is clearly meaningful. Whether it is true is a slightly
different matter. This pretty much depends on how you understand "easy". If
you consider writing a proxy class like the two presented complicated, you
will consider the statement false -- although you should agree to the
weaker version:

It's *possible* to turn [A] into (A,B).

This possibility has been demonstrated.


Best

Kai-Uwe Bux
 
R

roberts.noah

Kai-Uwe Bux said:
It's quite easy to turn [A] into (A,B) with no loss of
performance (on a good optimizing compiler).

The statement is clearly meaningful. Whether it is true is a slightly
different matter. This pretty much depends on how you understand "easy". If
you consider writing a proxy class like the two presented complicated, you
will consider the statement false -- although you should agree to the
weaker version:

It's *possible* to turn [A] into (A,B).

This possibility has been demonstrated.


Actually, what your proxy class did was to demonstrate that () could be
turned into [][] as what your proxy did was to create an adapter to
call () with the [][] interface...in other words the interface was
changed from () TO [][], not the other way. This is a rather important
distinction as it shows which was the more natural way to provide a
service. It also did a good job of illistrating how this added several
layers of totally unnecissary complexity.

At any rate, your assertion is without meaning. Of course it is
possible to call () with [][] or [][] with (). This does not mean the
two are equivilent in nature. Any claim otherwise is a failure in
logic. It is also possible to make operator * mean addition in C++,
and much more simply in fact. Is it useful? Is it introducing or
removing problems? Those are the questions to ask yourself.

No matter how you choose to alter the topic of discussion it was
certainly never asserted by anyone that it was not possible to call one
function with another. The *possibility* of generating the classes and
functions necissary to provide an interface for an artificially imposed
syntax was NEVER disputed. There is no end to the stupid things that
are *possible* to do. If that is all you have left to cling to then
there is nothing left to argue.
 
R

roberts.noah

Axter said:
I recommend using [][] over operator(), because it's easier to read,
and to maintain.
It's also easier to port back and forth with standard C-Style 2D
arrays.

See following link for efficient implementation:
http://code.axter.com/dynamic_2d_array.h

This is just a reiteration of the original code. At least in this case
though you aren't exposing internals of a class you have no control
over but only your own. The above class has no purpose. It protects
nothing. m_data may as well be public. That class doesn't even check
its inputs. The only thing you could say it does is keep track of its
2d dimensions...but you could do that with a struct.

Since it exposes its internal data to the public and provides no
protected interface to that data this class has next to no
encapsulation. This means all clients have to manage everything.
Better yet, you provide no way to get at necissary information that
would allow the clients to make sure they don't send bad input to the
class...but the class doesn't make sure its inputs are valid...in other
words the little encapsulation the class does offer is actually bad as
it means every client must also keep its own copy of the array bounds.

Since each client has to track its own copies of the bounds and do its
own error checking to make sure never to violate the exposed internals
of the class, this class is not only unnecissary it is also a very
inefficient implementation - a public pointer would be more efficient
and easier to maintain. Do some casts and get your [][] syntax...

Not very convincing.

About [][] being easier to read. Well that is a stylistic preference
but keep in mind two things:

1) In math the syntax is (a,b) - though usually subscripted.
2) Is it really that much easier to read that the added complexity
necissary to implement it adiquately is warranted?

About it being easier to maintain...I think you will need to elaborate
more on this idea as I see your above cited example as being an
absolute maintanence nightmare. Sure, the class is simple but its
clients are going to get really messy.
 
R

roberts.noah

Kai-Uwe Bux said:
reasons more specific than the
general philosophical yadda yadda about encapsulation.

Heh...it's no wonder I run into so much code rot in the real world.
Encapsulation is more that "general philisophical yadda yadda." It is
the sole purpose of classes and the very foundation of OOP. A class
that doesn't encapsulate its data is like a cell with no wall. When a
cell has no wall its insides just kind of meander about to god only
knows where....sort of like sauce in a bowl of spaghetti.

I can't believe I wasted so much time arguing with people that don't
even understand the importance of so simple a concept. If you don't
understand this concept and its importance then there is no way you can
understand the reasoning in the FAQ entry I cited or why returning
&array[x] is horrid.

No wonder...

hehehehe I've been bashing my head against the brick wall of
newbieville.
 
K

Kai-Uwe Bux

Kai-Uwe Bux said:
It's quite easy to turn [A] into (A,B) with no loss of
performance (on a good optimizing compiler).

The statement is clearly meaningful. Whether it is true is a slightly
different matter. This pretty much depends on how you understand "easy".
If you consider writing a proxy class like the two presented complicated,
you will consider the statement false -- although you should agree to the
weaker version:

It's *possible* to turn [A] into (A,B).

This possibility has been demonstrated.


Actually, what your proxy class did was to demonstrate that () could be
turned into [][] as what your proxy did was to create an adapter to
call () with the [][] interface...in other words the interface was
changed from () TO [][], not the other way.


This, I guess is an ambiguity in English. Gianni Mariani clearly meant that
the user could write

A[row][col]

and this expression would, by means of proxy magic, eventually result in a
call of A(row,col). Whether you want to call that a transformation from (,)
to [][] or a transformation from [][] to (,) seems a matter of perspective.
This is a rather important
distinction as it shows which was the more natural way to provide a
service. It also did a good job of illistrating how this added several
layers of totally unnecissary complexity.

"Several layers" is an exaggeration.

Whether the added complexity is unnecessary cannot be answered in the
absolute. Very much, depends on the context. However, I would agree that
one should not implement the proxy layer without good reason.

The stronger claim that was made is that this is easy (somewhat a matter of
opinion, taste, and cultural background) and can be done without
performance penalty (a purely technical claim also stated in the FAQ
[13.12]). I think, it is "easy" (some 40 lines of code for a little bit of
syntactic sugar is not that big a deal to me). Moreover, Gianni Mariani has
confirmed that, with modern compilers, one does not need to fear a loss in
performance. So, although we may have to agree to disagree on the easyness
part, there is a confirmation for the claim concerning performance.

At any rate, your assertion is without meaning. Of course it is
possible to call () with [][] or [][] with ().

So, you concede that it is true. Well, then it is, a fortiori, not without
meaning. If, however, you would be using the word "meaning" synonymous with
"relevance", then you have a point :)

The stronger claim, however, that proxies are easy to implement and can be
done without performance penalty, is clearly relevant. In particular, it
implies that the FAQ advice should be taken with a grain of salt as the
purely technical discussion of performance in the FAQ applies strictly to
simple minded, not proxy based implementations of the [][] interface (such
as the one first given to the OP).

This does not mean the two are equivilent in nature.

I don't think, I claimed that.


However, this sub-thread started with a slight disagreement about what would
constittue "changing the subject". I feel that that point became somewhat
mood.

In any case, I share your sentiment about the first matrix class as
presented to the OP.

As for proxy classes there are two established issues in this thread:

a) easyness.
b) performance.

I would suggest to ditch (a): it is clear that proxy classes add complexity.

I would suggest to declare that (b) should be re-evaluated when more data
points become available.

Finally, I would also like to open a new angle on proxies:

c) which opportunities do proxies as part of a matrix interface offer?

I think that it makes perfect sense to have a matrix class define types
row_vector and col_vector and to provide full fledged expression
templates / proxies that allow you to address the rows and columns in a
matrix. What I am thinking of is something like this: you could express a
row-operation as

A += 2*A[j];

This, of course, will not work for columns. So, I would suggest member
functions

row_vector_proxy row ( size_type );

and

col_vector_proxy col ( size_type );

Thus, the above becomes

A.row(i) += 2 * A.row(j);

and swapping two columns could be done via

std::swap( A.col(i), A.col(j) );

At some point, methinks, this can reduce the overall complexity of a matrix
class interface. In my own matrix class, I have member functions for
elementary row/col operations and row and column swaps. Maybe, proxies
actually could be useful in order to reduce complexity.


Best regards

Kai-Uwe Bux
 
K

Kai-Uwe Bux

Heh...it's no wonder I run into so much code rot in the real world.
Encapsulation is more that "general philisophical yadda yadda." It is
the sole purpose of classes and the very foundation of OOP. A class
that doesn't encapsulate its data is like a cell with no wall. When a
cell has no wall its insides just kind of meander about to god only
knows where....sort of like sauce in a bowl of spaghetti.

Exactly, and the FAQ item I referred to provided additional reasons that are
more specific in that they apply to matrix classes proper but not to all
classes. Here is the complete sentence:
I read the remarks about performance as giving reasons as to why you want
to keep the implementation details hidden -- reasons more specific than
the general philosophical yadda yadda about encapsulation.

I can't believe I wasted so much time arguing with people that don't
even understand the importance of so simple a concept. If you don't
understand this concept and its importance then there is no way you can
understand the reasoning in the FAQ entry I cited or why returning
&array[x] is horrid.

No wonder...

hehehehe I've been bashing my head against the brick wall of
newbieville.

Why do you insult me?


Regards

Kai-Uwe Bux
 
G

Gianni Mariani

Gianni Mariani wrote: ....
You truely are lost. Go back to school. A -> B therefore C is not
valid logic.

Another fact free statement, let's see how many facts we can actually
find in this posting.
Within entire FAQ, it has not given one thing you can do with "(,)" that
you cannot do with "[][]" yet it claims that "(,)" has a potential
upside. I still claim that there exists code that would take longer to
convert to "(,)" and will work with "[][]". I can even implement "[][]"
in tems of "(,)" which means that anything that you can do with "(,)"
can be done with "[][]".


You are wrong here ...

This is gong to be rich.
... again and again the point has just gone right past
you without one iota of understanding or even a hint that you realized
it was there. [][] by its definition creates an internal dependency
unless you create some, totally unnecissary to the task, proxy to
artificially impose the syntax paradigm in an abstract manner that in
the end just uses the more appropriate syntax of (x,y).

"unnecissary" - I'm not sure I think you know what that means.

Wether somthing is needed is determined by design.
In other words, and hopefully ones you can understand this time as they
are in the FAQ and have been reiterated several times here, there is no
way to change the form of the matrix storage once you have created [][]
as you have done.

.... Give me any implementation that takes a (,) and it can be turned
into a [][] with no loss in performance. They ARE THE SAME THING except
that [][] is more commonly found in numeric code written in C or C++
which means less porting, easier templates, yadda yadda, There is NO
GOOD REASON to use (,).
... You can't then decide that the computer would be
able to compute things faster if the matrix was stored in column major
form because all clients would then, necissarily, have to change! This
is unacceptable; a change to the private internals of a class should
NEVER affect its users.

Again, the only logical way you can get to this conclusion is if there
was somthing different between [][] and (,). You have already admitted
that there is no essential difference so another fact free statement.
... Creating a proxy answers this problem by
returning an object that just stores X and calls (x,y) on the matrix to
return the appropriate value. This is totally unnecissary and only
adds to the complexity of the program without giving any real benefit -

(x,y) does not work with legacy code or generic programming. This is a
major issue if you're looking for a general solution.
all it does is provide a particular syntax for minds too closed to
realize it is easier, and more efficient, the other way.

a) easier is a matter of opinion
b) efficient is a fallacy

More fact free statements.
... If there is
some reason why [][] MUST be used (some screwed up 3rd party lib,
orders from on high or whatever)

How about the C++ standard ?

float matricks[3][4];

.... try referencing matricks using (,).

There is a plethora of already written code that uses [][]. Unless
there is a good reason to change it, then don't.
... then you better provide it, and a
proxy (or adapter) seems like a good way of doing so, but starting from
scratch and imposing this mistake is a big mistake.

Consider this:
template <typename T>
struct matrix_traits;

template <typename w_Type >
struct matrix_traits< matrix< w_Type > >
{
typedef w_Type value_type;

static unsigned rows(
const matrix< w_Type > & i_matrix
)
{
return i_matrix.m_rows;
}

static unsigned columns(
const matrix< w_Type > & i_matrix
)
{
return i_matrix.m_columns;
}
};

template <typename w_Type, int w_rows, int w_columns>
struct matrix_traits< w_Type [w_rows][w_columns] >
{
typedef w_Type value_type;

static unsigned rows(
const w_Type (&i_array)[w_rows][w_columns]
)
{
return w_rows;
}

static unsigned columns(
const w_Type (&i_array)[w_rows][w_columns]
)
{
return w_columns;
}
};


template <typename TRESULT, typename T0, typename T1>
void add_matrix(
TRESULT & result,
const T0 & i_arg0,
const T1 & i_arg1
)
{
assert(
matrix_traits<TRESULT>::rows(result)
== matrix_traits<T0>::rows(i_arg0)
);
assert(
matrix_traits<T1>::rows(i_arg1)
== matrix_traits<T0>::rows(i_arg0)
);
assert(
matrix_traits<TRESULT>::columns(result)
== matrix_traits<T0>::columns(i_arg0)
);
assert(
matrix_traits<T1>::columns(i_arg1)
== matrix_traits<T0>::columns(i_arg0)
);

for (
unsigned l_row = matrix_traits<T0>::rows(i_arg0);
0 < l_row --;
)
{
for (
unsigned l_column = matrix_traits<T0>::columns(i_arg0);
0 < l_column --;
)
{
result[ l_row ][ l_column ] =
i_arg0[ l_row ][ l_column ]
+ i_arg0[ l_row ][ l_column ];
}
}
}

void add_test(
double (&ar)[3][4],
const double (&a0)[3][4],
const double (&a1)[3][4]
)
{
add_matrix( ar, a0, a1 );
}

void add_test(
matrix<float> & ar,
const double (&a0)[3][4],
const double (&a1)[3][4]
)
{
add_matrix( ar, a0, a1 );
}

The "add_matrix" method works equally as well with the matrix class as
it would a POD matrix. This would not be true if the matrix class
depended on (,) as the indexing syntax. This is a very significant issue.
The code you provided to the OP is a perfect example of how NOT to
write good objects as it exposed the internals of not only the class
itself but it also exposed the internals of a class to which you have
no control (std::vector)...and it did so in a manner that left the
class no way to protect its *private* parts from external influence.
This just murders all reason for using objects in the first place.

FYI, I was not going for the best code, I was going for quick example of
how you can make a dynamically sized matrix in the same spirit as
std::vector. Your points are well taken. However, you can complain
about code posted by others but you seem unwilling to post corrected
code. If these issues irk you so much, fix it.
Everyone does this from time to time but it is the better programmer
that can see that and learn from that mistake. Hopefully the OP is
reading this and understands better than you and can see that you made
a mistake there even if you can't (or are too proud to admit).

You're such a good programmer, we know, show us already.
[][] doesn't even make sense for anything other than a vector that
contains vectors anyway - one for the vector and one for the vector it
contains at that index.

Fact free statement, please explain why it makes no sense.
... There is no such operator as [][]

Yep, right again. That is 2 "[]" operators. The point is ?
> ... and imposing
one simply for the sake of imposing one is just silly, pointless, and
harmful.

You keep on saying it's an imposition to use [][], however, I have
stated at least 3 times now that it does make sense for legacy code and
generic programming, I have even given you an example of code that works
for both regular POD matrix and the dynamic matrix example I showed
earlier in this post. You have never refuted these statements, yet you
cast the whole idea as "rot".
... It's rot, pure and simple.

Is that a technical phrase ?
 
A

Axter

Axter said:
I recommend using [][] over operator(), because it's easier to read,
and to maintain.
It's also easier to port back and forth with standard C-Style 2D
arrays.

See following link for efficient implementation:
http://code.axter.com/dynamic_2d_array.h

This is just a reiteration of the original code. At least in this case
though you aren't exposing internals of a class you have no control
over but only your own. The above class has no purpose. It protects
nothing. m_data may as well be public. That class doesn't even check
its inputs. The only thing you could say it does is keep track of its
2d dimensions...but you could do that with a struct.

Since it exposes its internal data to the public and provides no
protected interface to that data this class has next to no
encapsulation. This means all clients have to manage everything.
Better yet, you provide no way to get at necissary information that
would allow the clients to make sure they don't send bad input to the
class...but the class doesn't make sure its inputs are valid...in other
words the little encapsulation the class does offer is actually bad as
it means every client must also keep its own copy of the array bounds.

Since each client has to track its own copies of the bounds and do its
own error checking to make sure never to violate the exposed internals
of the class, this class is not only unnecissary it is also a very
inefficient implementation - a public pointer would be more efficient
and easier to maintain. Do some casts and get your [][] syntax...

Not very convincing.

The purpose of the class, is not to provide bounds checking or extra
encapsolation.
It's purpose is to provide a basic generic frame work for an efficient
dynamic 2D array class that can be access using normal C-Style syntax.

Classes that attempt to do everything, end up doing nothing very
efficient.
About [][] being easier to read. Well that is a stylistic preference
but keep in mind two things:

1) In math the syntax is (a,b) - though usually subscripted.

Keep in mind, that C/C++ does not use that type of syntax, and I think
that idea is as bad as trying to make C++ code like BASIC.
Adding different syntax for contrived reasones, only serves to make the
code harder to read and understand. Stick with the KISS (Keep It
Simple Stupid) approach.
About it being easier to maintain...I think you will need to elaborate
more on this idea as I see your above cited example as being an
absolute maintanence nightmare. Sure, the class is simple but its
clients are going to get really messy.

I think you should provide an example as how this simple generic class
would be a nightmare to maintain, anymore then using a generic class
like std::vector.

IMHO, the idea of using operator() for a 2D array is a very bad idea,
and does not work well with the generic programming model. There is no
real legitimate reason for promoting operator() use over [][] in
generic programming.
On this matter, the C++ FAQ is very wrong.
 
R

roberts.noah

Axter said:
I think you should provide an example as how this simple generic class
would be a nightmare to maintain, anymore then using a generic class
like std::vector.

I don't. I think it sufficient to point out that, among other
important things, std::vector provides access to its bounds and your
class does not. Therefore every client of your class must have a copy
of the array boundaries while with std::vector they would not.
std::vector also does significantly more than your class including
growing in size and providing methods for sorting, searching, etc.
Your class not only doesn't do much, it doesn't do anything. It would
be MUCH more effecient to implement what you are doing with a simple
pointer and some casts.

I'll let the FAQ stand on its own. I don't need to defend it and it's
obvious to me now that I am arguing with a pack of newbies that refuse
to learn anything valueable. The FAQ was written by people smarter
and/or more experienced than either of us; I choose to learn from such
people so as to improve my efficiency as a professional
developer...especially when what they say is so well stated and
obviously true...and I am actually more convinced of that now since the
only ones saying I'm wrong don't seem to understand basic concepts
and/or have gotten completely lost by the topic of discussion.
 
P

peter koch

(e-mail address removed) skrev:
Axter said:
I think you should provide an example as how this simple generic class
would be a nightmare to maintain, anymore then using a generic class
like std::vector.

[snip]

I'll let the FAQ stand on its own. I don't need to defend it and it's
obvious to me now that I am arguing with a pack of newbies that refuse
to learn anything valueable. The FAQ was written by people smarter
and/or more experienced than either of us; I choose to learn from such
people so as to improve my efficiency as a professional
developer...especially when what they say is so well stated and
obviously true...and I am actually more convinced of that now since the
only ones saying I'm wrong don't seem to understand basic concepts
and/or have gotten completely lost by the topic of discussion.

Let me step in. So far as I see this thread is a rather bad attempt to
defend a position in the C++-faq. You seem to ignore the advice from
Gianni and you fail to respond to his quite reasonable arguments for
using operator []: namely that this allows reuse of existing code, e.g.
in a template library.
The C++ faq is very well written and invaluable for newbies and
programmers in the beginning of their C++ career, but that does not
mean that it is without flaws (*) or that it does not cut corners on
some of the more advanced stuff.
I've "known" Mariani on this newsgroup for quite some time now; he is
certainly not a newbie and is quite capable of writing and
understanding C++. If only you did care to read his posts and
understand them, this would be clear to you. I would recommend you to
cut down on your ego and learn from him.

/Peter

* If you go to the C++ faq you will find a list of recent changes.
Among them is a correction from ... Gianni Mariani.
 
A

Axter

I don't. I think it sufficient to point out that, among other
important things, std::vector provides access to its bounds and your
class does not. Therefore every client of your class must have a copy
of the array boundaries while with std::vector they would not.
std::vector also does significantly more than your class including
growing in size and providing methods for sorting, searching, etc.
Your class not only doesn't do much, it doesn't do anything. It would
be MUCH more effecient to implement what you are doing with a simple
pointer and some casts.

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.

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.

I'll let the FAQ stand on its own. I don't need to defend it and it's
obvious to me now that I am arguing with a pack of newbies that refuse
to learn anything valueable. The FAQ was written by people smarter
and/or more experienced than either of us;

Please speak for yourself. Your level of experience may coincide with
the above comment, but I would make no such assumptions with my
experience and expertise.
Moreover, even the best experts in any field make mistakes.
IMHO, this part of the C++ FAQ is incorrect.
 

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

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top