inheriting from std::vector bad practice?

J

James Kanze

On Apr 3, 5:35 pm, James Kanze <[email protected]> wrote:

[...]
From the context it is hard (at least for me) to know what the
OPs base abstraction actually is.

Is, or should be? From his code, the base class was
std::vector<Point2D>, so that's the base abstraction. Whether
this is a good design decision is a legitimate question---I
rather think unwrapped standard containers are too widely used
myself. But his question is basically, given this design
decision, whether it is appropriate to additional functionality
that isn't in std::vector (but might be appropriate for
std::vector<Point2D>). And that having decided to do so, is the
member function syntax the appropriate way to do so.

[...]
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.

That's always a problem when you use a standard container. He's
made the choice that his type will have random access iterators,
and will support insertion at the end (but not necessarily
elsewhere) in ammortized constant time.
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.

He can't switch. Ever. But why would he think he could. You
can't normally modify a base class (except maybe to extend it);
what you expect to be able to switch is the derived class. The
base class defines your contract. By definition, it's not an
implementation detail.

As he presented the problem, he has guaranteed random access
iterators (for example). It may be that he's guaranteeing more
than he should---in general, the less you guarantee, the better.
But that's a separate question from the one he asked.

Note that using composition, then using a typedef for the
iterator, has the same problem. I have a couple of classes that
"wrap" the iterator precisely for this reason.
 
J

James Kanze

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.

Or from discussions with Scott Meyer, which convinced me.

More generally, I don't have a particular fondness for free
functions. But in some cases, they are a better solution than
anything else. If the function can apply to any
std::vector<SomeType>, then a free function seems most
appropriate. You're not introducing a new type, with additional
functionality which isn't present in the base class; you're
introducing new functionality over an existing type (or types).
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).

You've lost me again. std::vector already has an operator[], so
providing a new one *isn't* augmenting the interface, it's
changing it. Unless, of course, you're somehow weakening the
pre-conditions, or strengthening the post-conditions of the
function. And of course, operator[] has to be a member, so you
really have no choice.
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);

A vector which uses 1-based indexing isn't an std::vector, so
inheritence doesn't really come into consideration. It might
be implemented in terms of a std::vector, but that would use
containment, and not inheritance.
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.

Agreed, but it doesn't work using inheritance either. You're
defining a totally new, unrelated type. If std::vector appears
at all, it is as part of the implementation (a private data
member).
 
J

James Kanze

[...]
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.

But don't stop thinking in hierarchial terms as well. One size
doesn't fit all: for some things, a "pure" OO approach is best,
for others, a functional approach, or a procedural approach, or
whatever. The more different approaches you master, the more
likely you are to find the best solution.
 
J

James Kanze

Steve Chow ha scritto:
Originally I had a bunch of related functions that all took a vector
of Point2D as their argument.
Point2D findGreatestDistance(std::vector<Point2D>& points);
[...]
So in review:
[...]
c.) free floating + generic (so it can take anything with an
iterator?)
Or, as was suggested to you, you could make the calculation of
the distance between two points generic as well, which results
in two template parameters (one for the two iterators, another
one for the distance functor). That's in the spirit of the
algorithms provided by the standard library.

Unless there's some need for making it generic, that's just
extra complication. What does make sense *is* to write the
function to take iterators, rather than the container, since 1)
this will make making it generic easier, if the need later
arises, 2) this will allow calculating the greatest distance
over subpaths, without having the create a new array, and 3)
this is simply more idiomatic C++. In practice, it's mainly the
third reason, and one could argue that this isn't really a good
idiom, even if it's ubiquous. But that's the way things are.

(PS: how is it that someone posting from an Austrian address,
with a good Austrian family name like Hackl, has his system set
up to respond in Italian:)?)
 
K

Kai-Uwe Bux

Leigh said:
James Kanze said:
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).

You've lost me again. std::vector already has an operator[], so
providing a new one *isn't* augmenting the interface, it's
changing it. Unless, of course, you're somehow weakening the
pre-conditions, or strengthening the post-conditions of the
function. And of course, operator[] has to be a member, so you
really have no choice.

When I say "augmenting interfaces" I also I include "adjusting
interfaces". I am neither strengthening nor weakening conditions as LSP
still holds and either the std::vector operator[] or the derived
operator[] can be used depending on the context.
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);

A vector which uses 1-based indexing isn't an std::vector, so
inheritence doesn't really come into consideration. It might
be implemented in terms of a std::vector, but that would use
containment, and not inheritance.
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.

Agreed, but it doesn't work using inheritance either. You're
defining a totally new, unrelated type. If std::vector appears
at all, it is as part of the implementation (a private data
member).

It does work using inheritance as the lower bound (1 in this example) is
stored as state in the derived class (this is Stroustrup's example not
mine) and is used if the derived class operator[] is called.

Just for concreteness (so that I can follow), are you proposing something
like this:

template < typename T >
class based_vector : public std::vector<T> {

std::vector<T>::size_type base;

public:

based_vector ( std::vector<T>::size_type b )
: std::vector<T> ()
, base ( b )
{}

T const & operator[] ( std::vector<T>::size_type n ) const {
assert( base <= n );
return ( std::vector<T>::eek:perator[]( n - b ) );
}

... // non-const version, at()

};


Best

Kai-Uwe Bux
 
K

Kai-Uwe Bux

Stuart said:
Kai-Uwe Bux said:
Leigh said:
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).
You've lost me again. std::vector already has an operator[], so
providing a new one *isn't* augmenting the interface, it's
changing it. Unless, of course, you're somehow weakening the
pre-conditions, or strengthening the post-conditions of the
function. And of course, operator[] has to be a member, so you
really have no choice.
When I say "augmenting interfaces" I also I include "adjusting
interfaces". I am neither strengthening nor weakening conditions as LSP
still holds and either the std::vector operator[] or the derived
operator[] can be used depending on the context.

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);
A vector which uses 1-based indexing isn't an std::vector, so
inheritence doesn't really come into consideration. It might
be implemented in terms of a std::vector, but that would use
containment, and not inheritance.

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.
Agreed, but it doesn't work using inheritance either. You're
defining a totally new, unrelated type. If std::vector appears
at all, it is as part of the implementation (a private data
member).

It does work using inheritance as the lower bound (1 in this example) is
stored as state in the derived class (this is Stroustrup's example not
mine) and is used if the derived class operator[] is called.

Just for concreteness (so that I can follow), are you proposing something
like this:

template < typename T >
class based_vector : public std::vector<T> {

std::vector<T>::size_type base;

public:

based_vector ( std::vector<T>::size_type b )
: std::vector<T> ()
, base ( b )
{}

T const & operator[] ( std::vector<T>::size_type n ) const {
assert( base <= n );
return ( std::vector<T>::eek:perator[]( n - b ) );
}

... // non-const version, at()

};


Best

Kai-Uwe Bux

If that is what is being proposed, it violates LSP -- because a
based_vector can be passed to a function expecting a vector but it can't
be used in every way a vector can (in particular, the function can't
access its 0th element). In other words, it's not substitutable for a
vector.

Could you provide an example? I was thinking along the same lines, and
pondered the following:

template < typename ArithmeticType >
ArithemticType total_sum ( std::vector<ArithmeticType> const & v ) {
typedef typename std::vector<ArithmeticType>::size_type size_type;
ArithmeticType result = 0;
for ( size_type n = 0; n < v.size(); ++ n ) {
result += v[n];
}
return ( result );
}

Now, if you pass a based_vector<int> into that function, I think, it will
behave "just fine". Strangely enough, the reason is that the member
functions involved are _not_ virtual.

Now, I think there are several possible reactions to this phenomenon. One is
to rethink the role of LSP another is to condemn the public derivation from
std::vector because the above seems strange and unexpected (and a third
would be to adjust expectations:).


Best

Kai-Uwe Bux
 
I

Ian Collins

I can understand in some cases preferring private inheritance over
composition if there is a need to access protected members of the
inherited class -- but I'd guess that the internals of std::vector are
private, so why inherit? (other than to save some typing)

I guess there isn't.

I had to make that call the other day, I wanted an associative array
with a const operator[], so I derived privately from std::map and added
a 'using operator[]" and the new const operator. I could just as easily
used composition, but I thought the reduction in typing made the code
clearer.
 
K

Keith H Duggar

[...]
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.

Is, or should be? From his code, the base class was
std::vector<Point2D>, so that's the base abstraction. Whether
this is a good design decision is a legitimate question---I
rather think unwrapped standard containers are too widely used
myself. But his question is basically, given this design
decision, whether it is appropriate to additional functionality
that isn't in std::vector (but might be appropriate for
std::vector<Point2D>). And that having decided to do so, is the
member function syntax the appropriate way to do so.

What I had in mind (and what I thought Alf had in mind) was more
that the original context of his first post seemed to be more a
"is this a good way" post. Ie I was assuming that he has some
other actual semantic context that we don't fully know, and he
is asking about the appropriateness of this solution in that
context even though we don't know it.

So above I was just pointing out (the somewhat obvious) fact
that (at least for me) it's hard to know the actual semantic
context he cares about without further input from him. Case in
point I'm somewhat doubtful that in his underlying context he
actually knowingly wants to provide the semantic guarantees
that public inheritance from std::vector gives.
That's always a problem when you use a standard container. He's
made the choice that his type will have random access iterators,
and will support insertion at the end (but not necessarily
elsewhere) in amortized constant time.

Well, that's what I'm wondering. Ie did he intentionally want
to provide those guarantees or is it something he wasn't fully
aware of and hadn't thought through?
He can't switch. Ever. But why would he think he could. You
can't normally modify a base class (except maybe to extend it);
what you expect to be able to switch is the derived class. The
base class defines your contract. By definition, it's not an
implementation detail.

Yes, I understand. But I'm "reading between the code lines"
here to explore the actual semantic context he is trying to
provide and to help make him better aware of issues that he
might not be aware of.
As he presented the problem, he has guaranteed random access
iterators (for example). It may be that he's guaranteeing more
than he should---in general, the less you guarantee, the better.
But that's a separate question from the one he asked.

I don't think it is a separate question. I think that is
entirely the point of the very subject of this thread ie
"bad practice [or not]". I think he is asking us to discuss
the issues that arise and certainly semantic guarantees
regarding iterators, memory layout, etc come up when you
inherit from STL containers (precisely because they are
documented by a standard). I don't think he was asking us
to discuss just this /one specific/ implementation, do you?
Note that using composition, then using a typedef for the
iterator, has the same problem. I have a couple of classes that
"wrap" the iterator precisely for this reason.

How exactly does wrapping the iterator provide a barrier to
assumptions regarding invalidation semantics? Do you document
the invalidation semantics for your "wrapped" iterators? And
do you document the complexity of the operations? etc.

It seems to me, given the current version of C++ (ie without
concepts etc) that documentation (rather than code, wrapping or
otherwise) is the primary source of such semantics.

KHD
 
K

Keith H Duggar

On Apr 3, 12:33 pm, Stuart Golodetz<[email protected]> wrote:
[...]

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.

But don't stop thinking in hierarchial terms as well. One size
doesn't fit all: for some things, a "pure" OO approach is best,
for others, a functional approach, or a procedural approach, or
whatever. The more different approaches you master, the more
likely you are to find the best solution.

Yes, thanks for pointing that out. Really what I am trying to
encourage is that he "vigorously immerse himself in flat
relational and functional thinking" for a time. The hope being
that he will learn to recognize problems for which those ways
and methods are superior to OOP.

Anyhow, thanks again for quite rightly pointing out that one
benefits greatly from mastering multiple approaches.

KHD
 
J

James Kanze

On Apr 5, 6:27 pm, James Kanze <[email protected]> wrote:

[...]
Well, that's what I'm wondering. Ie did he intentionally want
to provide those guarantees or is it something he wasn't fully
aware of and hadn't thought through?

I understand. In a lot of ways, I think I agree with you. At
least, I don't derive from standard containers in header files.
I may have been being a bit too indirect: he has made a choice
to provide a specific interface. Whether it is a good choice,
or even an intentional choice, I don't know (but I suspect that
I could make a pretty good guess---probably similar to yours).

And of course, there's always the possiblity that this is, in
fact, just a helper class, defined in a source file, rather than
a header, where he's in control of everything.

(Seriously, I think your points are good. I'm just in one of
myh ornerary moods, where I try to disagree with everyone.)

[...]
How exactly does wrapping the iterator provide a barrier to
assumptions regarding invalidation semantics?

I wasn't thinking so much of invaliation, as of iterator
category. The wrapper only provides a forward iterator, even
though the underlying iterator is (at present, at least) a
random access iterator.
Do you document the invalidation semantics for your "wrapped"
iterators? And do you document the complexity of the
operations? etc.

In the case in question, the underlying container is immutable
(once the iterators are made available), so invalidation isn't
an issue. But in general, you're right. One should never
provide an iterator without documenting when and if it might be
invalidated. (With regards to complexity: I expect all of the
operations that an iterator supports to have constant time.)
It seems to me, given the current version of C++ (ie without
concepts etc) that documentation (rather than code, wrapping
or otherwise) is the primary source of such semantics.

Largely. Still, if you don't support operator+=, then there's
no issue in how much time it takes:). And even concepts only
go so far; I don't think they can express complexity guarantees,
for example, and they can't express all of the required semantic
guarantees (e.g. concerning the semantics of assignment and
copy, for example).
 
J

James Kanze

"Stuart Golodetz" <[email protected]> wrote in message

[...]
I think that in Java (correct me if I am wrong) all
"overridden" functions are in effect virtual so LSP would be
broken in that case for Java? Silly Java.

Just for the record, in Java, you can declare a function final,
and it can't be overridden. In well written Java, most
functions are declared final.

It's interesting to note that this is one thing that is missing
in C++: once a function is virtual, there's no way of saying
that your implementation can't be overridden.
 
A

Alf P. Steinbach

* Leigh Johnston:
Pete Becker said:
James said:
It's interesting to note that this is one thing that is missing
in C++: once a function is virtual, there's no way of saying
that your implementation can't be overridden.

There will be in C++0X:

struct B1
{
virtual void f [[final]] ();
};

strange place to put it, wouldn't

virtual final void f();

or

virtual void f() final;

be better?

I cannot give a coherent reason why that position is wrong, it just
looks wrong to me. :)

Don't know about which positions are allowed, I agree with you that it would be
better up front. But the [[ ]] syntax is nice. It's essentially the same as
Microsoft pioneered in Visual C++ for the same general purpose, so it's almost
existing practice that will be standardized.

It would be interesting to get some comments about how much the C++0x syntax
overlaps with the Visual C++ one, if at all.

But at least it's very similar. :) And a general mechanism. That's good.


Cheers,

- Alf
 
A

Alf P. Steinbach

* Leigh Johnston:
Alf P. Steinbach said:
* Leigh Johnston:
James Kanze wrote:

It's interesting to note that this is one thing that is missing
in C++: once a function is virtual, there's no way of saying
that your implementation can't be overridden.


There will be in C++0X:

struct B1
{
virtual void f [[final]] ();
};


strange place to put it, wouldn't

virtual final void f();

or

virtual void f() final;

be better?

I cannot give a coherent reason why that position is wrong, it just
looks wrong to me. :)

Don't know about which positions are allowed, I agree with you that it
would be better up front. But the [[ ]] syntax is nice. It's
essentially the same as Microsoft pioneered in Visual C++ for the same
general purpose, so it's almost existing practice that will be
standardized.

It would be interesting to get some comments about how much the C++0x
syntax overlaps with the Visual C++ one, if at all.

But at least it's very similar. :) And a general mechanism. That's good.


Cheers,

I have never seen this [[ ]] syntax before in VC++, can you give me an
example?

Visual C++ uses single square brackets for attributes.

Here's a Microsoft example, combining attritutes and some custom keywords:


<code>
// evh_native.cpp
#include <stdio.h>

[event_source(native)]
class CSource {
public:
__event void MyEvent(int nValue);
};

[event_receiver(native)]
class CReceiver {
public:
void MyHandler1(int nValue) {
printf("MyHandler1 was called with value %d.\n", nValue);
}

void MyHandler2(int nValue) {
printf("MyHandler2 was called with value %d.\n", nValue);
}

void hookEvent(CSource* pSource) {
__hook(&CSource::MyEvent, pSource, &CReceiver::MyHandler1);
__hook(&CSource::MyEvent, pSource, &CReceiver::MyHandler2);
}

void unhookEvent(CSource* pSource) {
__unhook(&CSource::MyEvent, pSource, &CReceiver::MyHandler1);
__unhook(&CSource::MyEvent, pSource, &CReceiver::MyHandler2);
}
};

int main() {
CSource source;
CReceiver receiver;

receiver.hookEvent(&source);
__raise source.MyEvent(123);
receiver.unhookEvent(&source);
}
</code>


Cheers & hth.,

- Alf
 
N

Nick Keighley

eeek!


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

Is there a better way I should be doing this?
http://en.wikipedia.org/wiki/Delegation_(programming)


I have difficulties in seeing what you mean; especially with the advice you
give below.

I must admit the bio-weapon reference confused me...

Ok, lets say we had:

  class Path {

   std::vector<Point2D>

um. shouldn't that have a name?

  public:

   Path();
   ~Path();
   Point2D findGreatestDistance();
   /* related functions */

  };

How does that limit the knowledge of findGreastedDistance to those in need
to know?

it limits access to the vector


--
Nick Keighley

Let q(x) be a property provable about objects x of type T.
Then q(y) should be true for objects y of type S where S is a subtype
of T.
 
N

Nick Keighley

* Leigh Johnston:

didn't you start being rude first?

could you expand on that for the benefit of those of use who are not
quite so wise in C++ design principles?

[...]
Assume that you're right about my bodily contents. Does that help your argument?

No, it does not: it is a fallacy to attack the person.

no, it's rude but it isn't a fallacy

Let's mark this up as Fallacy #1.


Sometimes interface augmentation is a good idea, but in this case there is no
interface augmentation. Mentioning interface agumentation is just a strawman
argument, which is a fallacy. Let's mark this up as Fallacy #2.


This is just an appeal to authority.

I've never quite understood why it is wrong to quote people that might
know something about a subject

Which is a fallacy even when it's done
properly with references. Let's mark this as Fallacy #3.


No. std::vector is a generic type, a template type. The OP is not augmenting
std::vector.

he's augmenting std::vector<Point> which *is* a type



nick keighley
 
A

Alf P. Steinbach

* Nick Keighley:
didn't you start being rude first?

Depends on your definition of "rude", but who cares. I was precise.

<url: http://en.wikipedia.org/wiki/Bullshit#Distinguished_from_lying>

<quote>
"Bullshit" does not necessarily have to be a complete fabrication; with only
basic knowledge about a topic, bullshit is often used to make the audience
believe that one knows far more about the topic by feigning total certainty or
making probable predictions. It may also merely be "filler" or nonsense that, by
virtue of its style or wording, gives the impression that it actually means
something.

In his essay on the subject, William G. Perry called bull[shit] "relevancies,
however relevant, without data" and gave a definition of the verb "to
bull[shit]" as follows:

To discourse upon the contexts, frames of reference and points of
observation which would determine the origin, nature, and meaning of data if one
had any. To present evidence of an understanding of form in the hope that the
reader may be deceived into supposing a familiarity with content.[6]

The bullshitter generally either knows the statements are likely false,
exaggerated, and in other ways misleading or has no interest in their factual
accuracy one way or the other. "Talking bullshit" is thus a lesser form of
lying, and is likely to elicit a correspondingly weaker emotional response:
whereas an obvious liar may be greeted with derision, outrage, or anger, an
exponent of bullshit tends to be dismissed with an indifferent sneer.
could you expand on that for the benefit of those of use who are not
quite so wise in C++ design principles?

Huh. Benefits of a bad technique?

[...]
Assume that you're right about my bodily contents. Does that help your argument?

No, it does not: it is a fallacy to attack the person.

no, it's rude but it isn't a fallacy

It depends. When the personal attack is made as an argument (as above) or in
direct support of an argument, then it is a fallacy known as "Personal attack".
When it's made to discredit a person, as the above also was, then it's a fallacy
known as "Poisoning the well". So in a sense you're right. It was not a fallacy,
it was two fallacies, but hey.

<url: http://www.nizkor.org/features/fallacies/index.html#index> has a good
index of common fallacies, including discussion of the two above.

I've never quite understood why it is wrong to quote people that might
know something about a subject


he's augmenting std::vector<Point> which *is* a type

Only if you assume that the std::vector<Point> was intentional. We have the OP's
own statement that it wasn't, that it was only an implementation detail, where
only the push_back method was used.


Cheers & hth.,

- Alf
 
K

Kai-Uwe Bux

Alf said:
* Nick Keighley:
* Leigh Johnston:
* Leigh Johnston:
* Alf P. Steinbach:
* Leigh Johnston: [...]
and Bjarne Stroustrup agrees.
This is just an appeal to authority.

I've never quite understood why it is wrong to quote people that might
know something about a subject

See <url:
http://www.nizkor.org/features/fallacies/appeal-to-authority.html>.
[...]

I love the irony of citing an authority on the appeal to authority fallacy.
That's just a great display of wit.


BTW: from the top of that page:

Description of Appeal to Authority

An Appeal to Authority is a fallacy with the following form:

1. Person A is (claimed to be) an authority on subject S.
2. Person A makes claim C about subject S.
3. Therefore, C is true.

This fallacy is committed when the person in question is not a legitimate
authority on the subject. More formally, if person A is not qualified to
make reliable claims in subject S, then the argument will be fallacious.

So, according to that, calling an appeal to authority fallacious is to
question whether the person is a legitimate authority on the subject.


Best

Kai-Uwe Bux
 
A

Alf P. Steinbach

* Kai-Uwe Bux:
Alf said:
* Nick Keighley:
* Leigh Johnston:
* Leigh Johnston:
* Alf P. Steinbach:
* Leigh Johnston: [...]
and Bjarne Stroustrup agrees.
This is just an appeal to authority.
I've never quite understood why it is wrong to quote people that might
know something about a subject
See <url:
http://www.nizkor.org/features/fallacies/appeal-to-authority.html>.
[...]

I love the irony of citing an authority on the appeal to authority fallacy.
That's just a great display of wit.

Sorry, it was unintentional humor. It's just a reference with the requested
information.

BTW: from the top of that page:

Description of Appeal to Authority

An Appeal to Authority is a fallacy with the following form:

1. Person A is (claimed to be) an authority on subject S.
2. Person A makes claim C about subject S.
3. Therefore, C is true.

This fallacy is committed when the person in question is not a legitimate
authority on the subject. More formally, if person A is not qualified to
make reliable claims in subject S, then the argument will be fallacious.

So, according to that, calling an appeal to authority fallacious is to
question whether the person is a legitimate authority on the subject.

No, you have to read on, or see the Wikipedia article.

However I think you're right that the argument wasn't the fallacy that's known
as "appeal to authority" (as I wrote that it was), although it was literally
appealing to authority.

It was more like a combination of stating that situation A is an unrelated but
in some respects similar situation B, and that a generalized and misleading
paraphrase of authority X's comments about a situation C similar to B, applies
to A -- anyone who cares who to identify all the fallacies involved has my
respect as fallacy-hunter.


Cheers & hth.,

- Alf (evidently not an authority on fallacies, names of)
 
N

Nick Keighley

* Nick Keighley:


Depends on your definition of "rude", but who cares. I was precise.

must be a cultural thing. Where I'm from its rude. I'm not saying I
wouldn't use it but I'd use it knowing I was being rude. It seems odd
to me to tell someone they are bullshitting and then complain of
rudeness when they say you are full of shit!

But whatever.

no benefits of explanation (are we speaking the same language?)

perhaps you you could explain *why* it is bad. Or are we just supposed
to accept your god-like authority?

It depends. When the personal attack is made as an argument (as above) or in
direct support of an argument, then it is a fallacy known as "Personal attack".
When it's made to discredit a person, as the above also was, then it's a fallacy
known as "Poisoning the well". So in a sense you're right. It was not a fallacy,
it was two fallacies, but hey.




See <url:http://www.nizkor.org/features/fallacies/appeal-to-authority.html>.

yeah. I've heard of it. If we were discussing relativity would it be
wrong to mention Einsteins opinions on the subject?
Only if you assume that the std::vector<Point> was intentional. We have the OP's
own statement that it wasn't, that it was only an implementation detail, where
only the push_back method was used.

I must admit delegation seemed the most obvious answer to me
 
A

Alf P. Steinbach

* Nick Keighley:
must be a cultural thing. Where I'm from its rude. I'm not saying I
wouldn't use it but I'd use it knowing I was being rude. It seems odd
to me to tell someone they are bullshitting and then complain of
rudeness when they say you are full of shit!

I said a statement was bullshit, and it was.

You're saying I said someone is bullshitting. That is at best misleading, since
it is a statement about a person. But considering what you're writing below,
which is a pure personal attack, I think you intended also the above as such.

In other words, you're trolling.

But whatever.


no benefits of explanation (are we speaking the same language?)

perhaps you you could explain *why* it is bad.

It has been explained in detail by several posters in this thread (including
contributions from me).

If that's not good enough for you, then pick up any good book on design.

Or are we just supposed to accept your god-like authority?

OK, "we" => you're schizoid or have grand delusions of being royal, "your
god-like authority" => you're a troll, and a pretty stupid one to try to make
that argument in this group.


Cheers & hth.,

- Alf
 

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,755
Messages
2,569,534
Members
45,008
Latest member
Rahul737

Latest Threads

Top