inheriting from std::vector bad practice?

J

James Kanze

* Leigh Johnston:

[...]
Well, the most important one is still missing:
0. Is the class derivation an implementation detail?
If so then exposing it as public, even as a public member instead of
as a base class,
0.A. Introduces needless ways that bugs can creep in. E.g., when deriving
from std::vector<T>, then client code may use iterators incorrectly.

In what way? IIUC, the argument is that the base abstraction
*is* std::vector<Point2D>. In that case, all that the
derivation does is introduce a few extra convenience functions.
And while the idiomatic way of doing this in C++ is by means of
free functions, rather than derivation, I don't see how using
derivation for this can possibly lead to something like misuse
of the iterators.
 
A

Alf P. Steinbach

* James Kanze:
Strangely enough, I have to agree with Leigh here. (Doesn't
happen very often.) From what little we know of the global
context, this seems very much like what I would call "interface
augmentation". My only objection to the derivation is that in
C++ (unlike the case in e.g. Java), the idiomatic form of
interface augmentation is by using free functions: we have
std::sort, rather than std::vector<>::sort, etc.

In addition to the code itself we have the OPs statement that std::vector<Point>
is just an arbitrary implementation detail, where all he uses is push_back.

It's not an intended interface.

And with no intended interface there's no augmentation.


Cheers & hth.,

- Alf
 
A

Alf P. Steinbach

* James Kanze:
* Leigh Johnston:
[...]
3. A standard library container destructor is not virtual so
you cannot delete the associated object via a pointer to the
container (base class).
http://www.i42.co.uk/stuff/mutable_set.htm
Well, the most important one is still missing:
0. Is the class derivation an implementation detail?
If so then exposing it as public, even as a public member instead of
as a base class,
0.A. Introduces needless ways that bugs can creep in. E.g., when deriving
from std::vector<T>, then client code may use iterators incorrectly.

In what way? IIUC, the argument is that the base abstraction
*is* std::vector<Point2D>.

It isn't in the case we were discussing, and it certainly isn't for the context
of point 0.A above where the class derivation is an implementation detail.


Cheers & hth.,

- Alf
 
J

James Kanze

"James Kanze" <[email protected]> wrote in message

[...]
I don't care whether you would accept it in a code review or
not,

That's because we don't work in the same company, and I'm not
called upon to review your code. Code has to pass code review,
or be reworked until it does. It's as simple as that. And as
you've just been able to see, some people do feel strongly about
this issue, and it wouldn't surprise me if many places had such
rules in effect, and would not allow code which derived from a
standard container to pass review.

One thing is clear: using free functions rather than derivation
is a lot less likely to upset others who have to read your code
(unless they come from a Java background, and expect the C++ to
look like Java). IMHO, that's a very strong argument in favor
of free functions.
 
S

Steve Chow

Originally I had a bunch of related functions that all took a vector
of Point2D as their argument.
Point2D findGreatestDistance(std::vector<Point2D>& points);

However, this didn't strike me as a very C++/OO way to do things, so I
found a solution I was happy with in:
class Path : public std::vector<Point2D>
{
public:
   Path();
~Path();
   Point2D findGreatestDistance();
  /* related functions */

};
So in review:
a.) Leave it floating free. Perhaps put the class & free floating
function in the same namespace?
b.) Something like
class Path
{
public:
Path();
~Path();
Point2D furthestPoint();
void add(Point2D& p) // purely an example
{
_points.push_back(p);
}
private:
std::vector<Point2D> _points;
/* related functions */

};
c.) free floating + generic (so it can take anything with an
iterator?)
 
K

Keith H Duggar

* Leigh Johnston:
[...]
3. A standard library container destructor is not virtual so
you cannot delete the associated object via a pointer to the
container (base class).
http://www.i42.co.uk/stuff/mutable_set.htm
Well, the most important one is still missing:
0. Is the class derivation an implementation detail?
If so then exposing it as public, even as a public member instead of
as a base class,
0.A. Introduces needless ways that bugs can creep in. E.g., when deriving
from std::vector<T>, then client code may use iterators incorrectly.

In what way? IIUC, the argument is that the base abstraction
*is* std::vector<Point2D>.

From the context it is hard (at least for me) to know what the
OPs base abstraction actually is. For example, it seems clear
that a "Path" is a sequence of points, but a contiguous one?
That does seems like an implementation detail. It seems almost
inevitable that sometime soon we are going to find that other
implementations (list, set) are more appropriate.

However, since vector has been exposed as a public interface
clients are likely to take advantage of that. Ie they are going
to write code that works (or works well) only with random
access iterators, contiguous memory, constant time size, etc.
In that case, all that the
derivation does is introduce a few extra convenience functions.
And while the idiomatic way of doing this in C++ is by means of
free functions, rather than derivation, I don't see how using
derivation for this can possibly lead to something like misuse
of the iterators.

See above. One example that comes to mind is assuming the
iterators are random access. Another more insidious one would
happen if he had chosen std::list for the first round and
then switched to std::vector. In that case clients might have
taken advantage of the invalidation semantics of std::list for
example to assume that an erase from the middle would not
invalidate any other iterators besides the one erased. Then
when he switches the implementation to std::vector, bang!
Hard to find memory corruptions start to creep in.

KHD
 
S

Steve Chow

From the context it is hard (at least for me) to know what the
OPs base abstraction actually is. For example, it seems clear
that a "Path" is a sequence of points, but a contiguous one?
Mostly. As I explained in another post the sequence initially messed
up when dealing with
borders so I need to resort them. That's an unrelated issue that I've
cleared up though.
 
D

Daniel Pitts

The reason I avoided that was because I'd have to have to write a
public push_back function just to push_back to the private vector when
I wanted to add a point, no?
That's like saying "The reason I avoided putting a roof on this room is
that I'd have to provide a light-fixture when I want to light the room. "

Yes, you sometimes have to write code to "unhide" a subset of existing
code. You still should do it. You're path is *not* a vector of
points, it is implemented in terms of one.
I mean, it's trivial, but it just seemedlike a duplication.
It is not duplication, but delegation.
But if it's more correct I'm not really going to
argue. I tend to opt for the easy route a lot but have learned the
consequence of doing that a lot is a nightmarish maintenance
scenario.

Besides the poor semantics of that design, there is also risk in
deriving from a class which was not designed for such use (for example,
a class which does not have a virtual destructor).

That's right, classes have to be *designed* to be inheritable. It is an
all to common mistake (even by experienced programmers) to expect that
they can extend any class they choose. I personally only realized this
a few years ago when reading a Java concurrency book, and I've been
programming for nearly 20 years, almost 2/3rds of my life!
 
K

Keith H Duggar

James Kanze said:
One thing is clear: using free functions rather than derivation
is a lot less likely to upset others who have to read your code
(unless they come from a Java background, and expect the C++ to
look like Java). IMHO, that's a very strong argument in favor
of free functions.

Your fondness of free functions probably stems from the fact that you used
to be a C programmer (joke) or that <algorithm> is full of them which is
fine as those functions are generic whereas you can argue that an augmented
operator[] for std::vector is specific to that container and so quite
rightly should be part of a class augmenting std::vector especially as it
comes with state that is not dependent on the vector's state (so LSP still
holds).

So for a vector which supports 1-based indexing (instead of 0-based):

int f = bounded_vector[10];

is an improvement on than:

int f = access_bounded_vector(v, 1, 10);

This example simply doesn't work as a free function as what could be state
in a class (for the value 1 above) now has to be passed to the stateless
free function.

Your lack of imagination and inability to provide elegant free
function solutions probably stems from your OOP blinders. They
prevent you from grasping simple concepts such as overloading.
For example, the free function version of accessing a 1-based
vector type would not look like the unimaginative and verbose
junk you coded above, rather it would simply be

access(v,10)

just as it would be for 0-based vectors.

KHD
 
S

Steve Chow

Well -- in the case of the imaging example, I can't see why either class
would inherit from the other (an Image isn't a DataExtractor, or
vice-versa). I'm assuming the DataExtractor class is some sort of
functor, incidentally. The relationship seems to be that some other code
instantiates a DataExtractor, and uses it to extract data from an image.
Or something along those lines :) Either way, doesn't sound like there
should be an inheritance relationship between those two classes.
The reason it's I said it was murky was the dataExtractor class is
accessing (and) requires virtually all the private variables of the
image class. I have a get/set method for pretty much everything and
I'm using them everywhere. I mean, I have a flood method in
dataExtractor which get's a pointer to the pixeldata in image, gets
the size of the image, and performs a flood fill operation. I do this
to mark it visually and logically as already processed. But I also
obtain scanlines of the blob, create a binary duplication of the
flooded area, etc. The only way I can obtain this info is through a
flood operation. But flood fill? Flood sounds like it should be in the
image class, or maybe an image tools class, but it also does all this
specialized stuff that doesn't mean anything to any other program or
class.

I sometimes wish I had a formal education in this stuff. I'm self-
taught and I think it shows.
 
K

Keith H Duggar

The reason it's I said it was murky was the dataExtractor class is
accessing (and) requires virtually all the private variables of the
image class. I have a get/set method for pretty much everything and
I'm using them everywhere. I mean, I have a flood method in
dataExtractor which get's a pointer to the pixeldata in image, gets
the size of the image, and performs a flood fill operation. I do this
to mark it visually and logically as already processed. But I also
obtain scanlines of the blob, create a binary duplication of the
flooded area, etc. The only way I can obtain this info is through a
flood operation. But flood fill? Flood sounds like it should be in the
image class, or maybe an image tools class, but it also does all this
specialized stuff that doesn't mean anything to any other program or
class.

The difficulty you are facing is primarily one of perspective. I
encourage you stop thinking in hierarchical terms such as has-a,
inside, outside, belongs, contains, etc. Instead think in flat
relational and functional terms.

For example "flood fill" should not "be in" an image class. It
is an operator, a function, that maps one image (the source or
domain or argument) to another image (the output or co-domain
or result). In is not "in" anything rather it is a mapping or
a relation "between" values.

So a usage of flood fill might look like any of these

floodFill(tmp) ; //modify in-place
floodFill(src,tgt) ; //out by reference
floodFill(src,&tgt) ; //out by pointer
tgt = floodFill(src) ; //out by return
...

whichever is most appropriate for your designs. Perhaps even a
2D-iterator solution is appropriate. The important point though
is that floodFill is not "inside" or "part of" any class, object,
etc just as a myriad of other functions or not "in" something. For
example, is the sqrt function "inside" a double? Or a float? No.
Rather it is a mapping "between" numbers. Think algebraically,
mathematically, and in flat relational terms as functions that
operate /between/ objects mapping values to values.

Some keywords to further your studies if interested:

http://en.wikipedia.org/wiki/Binary_relation
http://en.wikipedia.org/wiki/Function_(mathematics)
http://en.wikipedia.org/wiki/Operator

KHD
 
K

Keith H Duggar

Mostly. As I explained in another post the sequence initially messed
up when dealing with
borders so I need to resort them. That's an unrelated issue that I've
cleared up though.

To clarify here by "contiguous" I was referring specifically to the
special memory layout of std::vector as opposed to say std::list.
Also a practical consequence the iterator semantics.

KHD
 
K

Keith H Duggar

The difficulty you are facing is primarily one of perspective. I
encourage you stop thinking in hierarchical terms such as has-a,
inside, outside, belongs, contains, etc. Instead think in flat
relational and functional terms.

For example "flood fill" should not "be in" an image class. It
is an operator, a function, that maps one image (the source or
domain or argument) to another image (the output or co-domain
or result). In is not "in" anything rather it is a mapping or
a relation "between" values.

So a usage of flood fill might look like any of these

   floodFill(tmp) ;  //modify in-place
   floodFill(src,tgt) ; //out by reference
   floodFill(src,&tgt) ; //out by pointer
   tgt = floodFill(src) ; //out by return
   ...

whichever is most appropriate for your designs. Perhaps even a
2D-iterator solution is appropriate. The important point though
is that floodFill is not "inside" or "part of" any class, object,
etc just as a myriad of other functions or not "in" something. For
example, is the sqrt function "inside" a double? Or a float? No.
Rather it is a mapping "between" numbers. Think algebraically,
mathematically, and in flat relational terms as functions that
operate /between/ objects mapping values to values.

Some keywords to further your studies if interested:

Oh, I forgot to give you one of my favorite introductions to,
among other things, algebraic type theory which will help you
understand these issues on a much deeper level. The series of
sixteen articles begins here:

http://www.jot.fm/issues/issue_2002_05/column5/

KHD
 
K

Keith H Duggar

Keith H Duggar said:
One thing is clear: using free functions rather than derivation
is a lot less likely to upset others who have to read your code
(unless they come from a Java background, and expect the C++ to
look like Java). IMHO, that's a very strong argument in favor
of free functions.
Your fondness of free functions probably stems from the fact that you
used
to be a C programmer (joke) or that <algorithm> is full of them which is
fine as those functions are generic whereas you can argue that an
augmented
operator[] for std::vector is specific to that container and so quite
rightly should be part of a class augmenting std::vector especially as it
comes with state that is not dependent on the vector's state (so LSP
still
holds).
So for a vector which supports 1-based indexing (instead of 0-based):
int f = bounded_vector[10];
is an improvement on than:
int f = access_bounded_vector(v, 1, 10);
This example simply doesn't work as a free function as what could be
state
in a class (for the value 1 above) now has to be passed to the stateless
free function.
Your lack of imagination and inability to provide elegant free
function solutions probably stems from your OOP blinders. They
prevent you from grasping simple concepts such as overloading.
For example, the free function version of accessing a 1-based
vector type would not look like the unimaginative and verbose
junk you coded above, rather it would simply be

just as it would be for 0-based vectors.

That is just plain garbage as v would be a std::vector if you are not using
inheritance to solve this so where would the index offset come from if not
passed to the access function? Having different access functions for
different offsets would be also be stupid. Try using your brain and/or
common sense before spouting such bullshit.

Poor Leigh, such pathetically limited imagination, intellect and
self-control. Try to open your mind. I know it's hard even for a
normal person, and for you it will be especially painful. I know
you need some hints let us try this: free functions are ONE tool
in the toolbox, NOT the ONLY tool.

There is another clue in my original post, the word "overloading".
Can you figure it out now? I see you are still blind, so another
clue is: no, v would NOT be std::vector. It would be, as stated
plainly, a "1-based vector type".

Ok, you are still lost and angry. Try to comprehend a last hint:
using free functions to extend functionality does not proscribe
using types to extend state. HTH!

KHD
 
K

Keith H Duggar

Keith H Duggar said:
messageOne thing is clear: using free functions rather than derivation
is a lot less likely to upset others who have to read your code
(unless they come from a Java background, and expect the C++ to
look like Java). IMHO, that's a very strong argument in favor
of free functions.
Your fondness of free functions probably stems from the fact that you
used
to be a C programmer (joke) or that <algorithm> is full of them which
is
fine as those functions are generic whereas you can argue that an
augmented
operator[] for std::vector is specific to that container and so quite
rightly should be part of a class augmenting std::vector especially as
it
comes with state that is not dependent on the vector's state (so LSP
still
holds).
So for a vector which supports 1-based indexing (instead of 0-based):
int f = bounded_vector[10];
is an improvement on than:
int f = access_bounded_vector(v, 1, 10);
This example simply doesn't work as a free function as what could be
state
in a class (for the value 1 above) now has to be passed to the
stateless
free function.
Your lack of imagination and inability to provide elegant free
function solutions probably stems from your OOP blinders. They
prevent you from grasping simple concepts such as overloading.
For example, the free function version of accessing a 1-based
vector type would not look like the unimaginative and verbose
junk you coded above, rather it would simply be
access(v,10)
just as it would be for 0-based vectors.
That is just plain garbage as v would be a std::vector if you are not
using
inheritance to solve this so where would the index offset come from if
not
passed to the access function? Having different access functions for
different offsets would be also be stupid. Try using your brain and/or
common sense before spouting such bullshit.
Poor Leigh, such pathetically limited imagination, intellect and
self-control. Try to open your mind. I know it's hard even for a
normal person, and for you it will be especially painful. I know
you need some hints let us try this: free functions are ONE tool
in the toolbox, NOT the ONLY tool.
There is another clue in my original post, the word "overloading".
Can you figure it out now? I see you are still blind, so another
clue is: no, v would NOT be std::vector. It would be, as stated
plainly, a "1-based vector type".
Ok, you are still lost and angry. Try to comprehend a last hint:
using free functions to extend functionality does not proscribe
using types to extend state. HTH!

You really are clueless aren't you? If you want a vector with an arbitrary
lower bound of 0, 1, 2, 3, ... , N are you proposing having N types and N
access() overloads or a templated access() to support a lower bound that is
determined at runtime and not compile time? This is patently absurd and is
the typical retarded bullshit I would expect to come from a programmer who
has recently discovered functional programming. Get a f**king clue.

LOL the art of strawman. One of the few things that come naturally
to you. Haven't you heard of the 0-1-N rule, Leigh? No, I suppose
not. That would require that you are actually educated. Well here

http://en.wikipedia.org/wiki/Zero_One_Infinity

go wikipeducate yourself a bit (maybe throw in a few googles) and
then see if you can practically apply the 0-1-N rule to the design
question you raise above.

But, I know this is hard for you and you're still lost and angry.
(As we can all plainly see.) So here is another hint: dynamic and
compile time solutions can coexist and can (this will be a total
shock to you) partition the 0-1-N space as we see fit.

Finally, as to the topic at hand, the choice of how to partition
the 0-1-N space between static vs dynamic state is /orthogonal/
to concept of using free functions to extend functionality and/or
types to extend state. Hint, we can code an "N-based vector type"
as simply as a "1-based vector type". HTH!

KHD
 
K

Keith H Duggar

Keith H Duggar said:
messagemessageOne thing is clear: using free functions rather than derivation
is a lot less likely to upset others who have to read your code
(unless they come from a Java background, and expect the C++ to
look like Java). IMHO, that's a very strong argument in favor
of free functions.
Your fondness of free functions probably stems from the fact that
you
used
to be a C programmer (joke) or that <algorithm> is full of them
which
is
fine as those functions are generic whereas you can argue that an
augmented
operator[] for std::vector is specific to that container and so
quite
rightly should be part of a class augmenting std::vector especially
as
it
comes with state that is not dependent on the vector's state (so
LSP
still
holds).
So for a vector which supports 1-based indexing (instead of
0-based):
int f = bounded_vector[10];
is an improvement on than:
int f = access_bounded_vector(v, 1, 10);
This example simply doesn't work as a free function as what could
be
state
in a class (for the value 1 above) now has to be passed to the
stateless
free function.
Your lack of imagination and inability to provide elegant free
function solutions probably stems from your OOP blinders. They
prevent you from grasping simple concepts such as overloading.
For example, the free function version of accessing a 1-based
vector type would not look like the unimaginative and verbose
junk you coded above, rather it would simply be
access(v,10)
just as it would be for 0-based vectors.
That is just plain garbage as v would be a std::vector if you are not
using
inheritance to solve this so where would the index offset come from if
not
passed to the access function? Having different access functions for
different offsets would be also be stupid. Try using your brain
and/or
common sense before spouting such bullshit.
Poor Leigh, such pathetically limited imagination, intellect and
self-control. Try to open your mind. I know it's hard even for a
normal person, and for you it will be especially painful. I know
you need some hints let us try this: free functions are ONE tool
in the toolbox, NOT the ONLY tool.
There is another clue in my original post, the word "overloading".
Can you figure it out now? I see you are still blind, so another
clue is: no, v would NOT be std::vector. It would be, as stated
plainly, a "1-based vector type".
Ok, you are still lost and angry. Try to comprehend a last hint:
using free functions to extend functionality does not proscribe
using types to extend state. HTH!
KHD
You really are clueless aren't you? If you want a vector with an
arbitrary
lower bound of 0, 1, 2, 3, ... , N are you proposing having N types and N
access() overloads or a templated access() to support a lower bound that
is
determined at runtime and not compile time? This is patently absurd and
is
the typical retarded bullshit I would expect to come from a programmer
who
has recently discovered functional programming. Get a f**king clue.
LOL the art of strawman. One of the few things that come naturally
to you. Haven't you heard of the 0-1-N rule, Leigh? No, I suppose
not. That would require that you are actually educated. Well here

go wikipeducate yourself a bit (maybe throw in a few googles) and
then see if you can practically apply the 0-1-N rule to the design
question you raise above.
But, I know this is hard for you and you're still lost and angry.
(As we can all plainly see.) So here is another hint: dynamic and
compile time solutions can coexist and can (this will be a total
shock to you) partition the 0-1-N space as we see fit.
Finally, as to the topic at hand, the choice of how to partition
the 0-1-N space between static vs dynamic state is /orthogonal/
to concept of using free functions to extend functionality and/or
types to extend state. Hint, we can code an "N-based vector type"
as simply as a "1-based vector type". HTH!

I am tired of your bullshit, you obviously lack the ability to get a clue.

From the big expanse of time (86 seconds) between my post and your
reply, we now have empirical evidence of your capacity to focus on
intellectual issues. I'm sorry that you suffer from ADHD, Leigh. I
wish you had been upfront about it in the first place. Then maybe
a more caring touch on my part in combination with your medication
might have enabled you to learn more effectively. Oh well.

KHD
 
K

Kai-Uwe Bux

Keith said:
So for a vector which supports 1-based indexing (instead of 0-based):

int f = bounded_vector[10];

is an improvement on than:

int f = access_bounded_vector(v, 1, 10);

This example simply doesn't work as a free function as what could be
state in a class (for the value 1 above) now has to be passed to the
stateless free function.

Your lack of imagination and inability to provide elegant free
function solutions probably stems from your OOP blinders. They
prevent you from grasping simple concepts such as overloading.
For example, the free function version of accessing a 1-based
vector type would not look like the unimaginative and verbose
junk you coded above, rather it would simply be

access(v,10)

just as it would be for 0-based vectors.

I don't quite understand. In the line

access( v, 10 ),

what is the type of v?

I was under the impression that Leigh Johnston is discussing the option of
not having a class for a 1-based container at all and using free-standing
access function to simulate the behavior. It appears that your access()
function is serving a different purpose. But maybe, I misunderstand you (or
both of you).


Best

Kai-Uwe Bux
 
K

Keith H Duggar

Keith said:
So for a vector which supports 1-based indexing (instead of 0-based):
int f = bounded_vector[10];
is an improvement on than:
int f = access_bounded_vector(v, 1, 10);
This example simply doesn't work as a free function as what could be
state in a class (for the value 1 above) now has to be passed to the
stateless free function.
Your lack of imagination and inability to provide elegant free
function solutions probably stems from your OOP blinders. They
prevent you from grasping simple concepts such as overloading.
For example, the free function version of accessing a 1-based
vector type would not look like the unimaginative and verbose
junk you coded above, rather it would simply be

just as it would be for 0-based vectors.

I don't quite understand. In the line

access( v, 10 ),

what is the type of v?

As the post says it is a "1-based vector type".
I was under the impression that Leigh Johnston is discussing
the option of not having a class for a 1-based container at all
and using free-standing access function to simulate the behavior.

Leigh is discussing a red herring and a strawman of his own out-
of-thin-air design in response to a point that James raised. To
reiterate, what James actually said was:

James said:
As someone else pointed out, the simplest and safest solution
is to follow the model in the STL, and use a free function for
the extended interface.

Notice the key word there /interface/. Instead of responding to
that point, Leigh decided to make up his own phantom and respond
to a case of extending /state/ instead. Of course, nobody here
in the discussion was advocating extending /state/ using /only/
free functions. They are part of a solution, a new type being
the other part. Whether that type has new state or not, and how
that distinct type is constructed (roll-your-own, composition,
inheritance, etc) are orthogonal design considerations.
It appears that your access() function is serving a different
purpose. But maybe, I misunderstand you (or both of you).

I think all you are missing are the various red herring, strawmen,
appeal to ignorance, excluded middle, etc logical fallacies that
Leigh compulsively displays with nearly every post.

KHD
 
K

Keith H Duggar

Keith H Duggar said:
Keith H Duggar wrote:
[...]
So for a vector which supports 1-based indexing (instead of 0-based):
int f = bounded_vector[10];
is an improvement on than:
int f = access_bounded_vector(v, 1, 10);
This example simply doesn't work as a free function as what could be
state in a class (for the value 1 above) now has to be passed to the
stateless free function.
Your lack of imagination and inability to provide elegant free
function solutions probably stems from your OOP blinders. They
prevent you from grasping simple concepts such as overloading.
For example, the free function version of accessing a 1-based
vector type would not look like the unimaginative and verbose
junk you coded above, rather it would simply be
access(v,10)
just as it would be for 0-based vectors.
I don't quite understand. In the line
access( v, 10 ),
what is the type of v?
As the post says it is a "1-based vector type".
Leigh is discussing a red herring and a strawman of his own out-
of-thin-air design in response to a point that James raised. To
reiterate, what James actually said was:
Notice the key word there /interface/. Instead of responding to
that point, Leigh decided to make up his own phantom and respond
to a case of extending /state/ instead. Of course, nobody here
in the discussion was advocating extending /state/ using /only/
free functions. They are part of a solution, a new type being
the other part. Whether that type has new state or not, and how
that distinct type is constructed (roll-your-own, composition,
inheritance, etc) are orthogonal design considerations.
I think all you are missing are the various red herring, strawmen,
appeal to ignorance, excluded middle, etc logical fallacies that
Leigh compulsively displays with nearly every post.

LOL. My first reply in this thread was:

"No in general it is not bad practice, Stroustrup does it in The C++
Programming Language (25.6.1 Adjusting Interfaces). The only thing you have
to watch out for is that a standard container's destructor is not virtual.

Seehttp://www.i42.co.uk/stuff/mutable_set.htmalso (something I wrote but
deriving from map/multimap instead of vector)."

This is not a strawman logical fallacy whatnot

Good, you reveal that you don't even know what that fallacy is.
Given that you are totally ignorant of what the fallacy is, you
are incapable of recognizing that you are committing it. Same
for the other fallacies I and others have pointed out to you.
you describe but a perfectly
valid counter-example to the claims made by others in this thread that you
should not derive publicly from the standard containers.

Which is of course completely irrelevant to the point now being
discussed which is James' suggestion to "use a free function for
the extended interface."

This is to be expected. Your ADHD makes it difficult for you
to stick with a linear thought. Your mind flitters back and
forth between details that are convenient for your personal
"now" interest rather than relevant to the discussion.
Who says that augmenting an interface cannot also involve extra
state as long as said state cannot be invalidated by mutating the
base class part of an object (LSP)?

Of course nobody said augmenting an interface cannot "involve"
extra state. Rather it is that extending an interface does not
/necessarily involve/ extra state. And if and when extra state
is expedient or required to implement the behavior, that this
is a separate concern from the interface itself.

In other words, this regards the classic separation between
interface and implementation. I would have expected the same
guy (Leigh) who cried so loudly about /abstract interfaces/
in a past thread would be able to understand that interface
and state are separate concerns.
You are the one spouting logical fallacies.

Again, given that you as much admitted you do not even know what
said fallacies are, do not even understand their definition nor
how to recognize them, how can you now rationally expect anyone,
even yourself, to take that final parting shot seriously at all?

KHD
 

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,755
Messages
2,569,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top