inheritance like Animal : List<Animal>

T

Tony Johansson

Hi!

I know all of the below construction marked 1,2,3 but I'm little unsure how
I should think when I have a
constuction like this
public class Animal : List<Animal>
{
....
}
Can somebody give me some guideline so I can understand this.


1.
public Car : SportCar
{
....
}

or create a generic class in this way
2.
public class MyVector<T>
{
....
}
or create a generic instance like this
3.
MyVector<int> = new MyVector<int>();

//Tony
 
P

Peter Duniho

Tony said:
Hi!

I know all of the below construction marked 1,2,3 but I'm little unsure how
I should think when I have a
constuction like this
public class Animal : List<Animal>
{
....
}

A class that is a List<T> of itself?

Surely that's not what you intend. I mean, it'll compile, but when
would you actually use that? And if you do in fact have an actual
scenario in mind, are you sure it's really worth the potential
confusion? (For example, it's likely that using composition, by making
Animal contain a List<Animal> rather than _being_ a List<Animal> would
make more sense)

Your other examples aren't helpful either. The first one seems
backwards (shouldn't "SportCar" inherit "Car"? do you really intend
that all cars that exist are sports cars?), and the second and third
don't appear to provide any additional insight into what question you're
trying to ask.

Please try to be more clear about your question. What are you really
trying to ask?

Pete
 
A

Andy O'Neill

Tony Johansson said:
Hi!

I know all of the below construction marked 1,2,3 but I'm little unsure
how I should think when I have a
constuction like this
public class Animal : List<Animal>
{
...
}
Can somebody give me some guideline so I can understand this.

You make class sportscar : car
Then you use it as a type for a list.
list mysportscars = new list<sportscars>

You ought to sit and read a decent book mate.
 
V

vanderghast

Even if in a Tree, each node can be seen as something with a List of nodes
under it (or null if it is a terminal node), a Node : List<Node> don't make
much sense, since the concept of a single, individual, node has generally
much different CONCERNS than when you have to though about the concept of a
list, a collection, an organized group (of nodes). And even if, somehow, you
are at a point of an algorithm where some node should be seen "as" a
list<node>, as the root of a sub-tree , then that list can be obtained
trough one of the property of the node, rather than by the essential nature
of a single individual node. So, rather than inheritance, I suspect you
rather want to simply OWNS a property returning a LIST, than to derive from
a LIST.


Vanderghast, Access MVP
 
R

Raja R Harinath

Hi,

Tony Johansson said:
Hi!

I know all of the below construction marked 1,2,3 but I'm little unsure how
I should think when I have a
constuction like this
public class Animal : List<Animal>
{
...
}

It is hard to read an 'is-a' like that in a meaningful way.

On the other hand,

public class Animal : IEnumerable<Animal> {}

"'Animal' implements a way to enumerate a set of 'Animal's" could be
used to signify parthenogenesis.

- Hari
 
P

Peter Duniho

Raja said:
[...]
public class Animal : IEnumerable<Animal> {}

"'Animal' implements a way to enumerate a set of 'Animal's" could be
used to signify parthenogenesis.

It _could_ be used that way. But it would still be poor design. First,
there's nothing about that to distinguish itself from other types of
reproduction. And in any case, no matter the type of reproductive
process, it's simply not true that the parent creature _is_ an
enumeration of the child creatures.

"Has a" is a much more natural relationship in that example than "is a".

Pete
 
R

Raja R Harinath

Hi,

Peter Duniho said:
Raja said:
[...]
public class Animal : IEnumerable<Animal> {}

"'Animal' implements a way to enumerate a set of 'Animal's" could be
used to signify parthenogenesis.

It _could_ be used that way. But it would still be poor design.
First, there's nothing about that to distinguish itself from other
types of reproduction.

Sure, I was trying to be somewhat facetious there.
And in any case, no matter the type of reproductive process, it's
simply not true that the parent creature _is_ an enumeration of the
child creatures.

A less strained example would be

XmlNode : IEnumerable<XmlNode>

Yes, an XmlNode is not _just_ an enumeration of its embedded XmlNodes,
but there is a "natural" notion of it containing child nodes.

Maybe I'm splitting hairs due to being influenced by Java, but I see a
difference between "inherits" (as a synonym for "is a") and "implements"
("has an aspect which is a").

- Hari
 
P

Peter Duniho

Raja said:
[...]
Maybe I'm splitting hairs due to being influenced by Java, but I see a
difference between "inherits" (as a synonym for "is a") and "implements"
("has an aspect which is a").

IMHO, that "influence" exists only if one takes the words "inherits" and
"implements" too literally. The fact is, to implement an interface
should also mean the type "is a", not "has a". In the general
guidelines of OOP design, there's not a third option, "has an aspect
which is a".

In C#, this is even made explicit, via the "is" operator, which returns
"true" for both concrete types and interfaces. Note also that the world
of OOP is not limited to Java or C# where one is forced to use
interfaces in order to accomplish something like multiple inheritance,
and in other languages the line between inherited types and implemented
interfaces is much more blurry.

Finally, there is the school of thought in OOP that inheritance of
implementation (e.g. Java's "extends") should be _strictly_ a private
affair, with non-implementation interfaces being the only visible
"inheritance" for a type. IMHO, that's a perfectly valid approach to
designing an OOP language (C++, C#, and Java don't support that kind of
design…though, C++ comes closest with public and private inheritance),
and OOP concepts such as "is a" and "has a" should still apply in a
context like that, which they could not if you treat inheritance of an
interface differently from inheritance of an implementation in terms of
object identity.

As far as the specific example of XmlNode goes, it seems to me that
having XmlNode inherit and implement IEnumerable<XmlNode> is a
potentially practical departure from a rigid OOP design (as could be
argued for any implementation of IEnumerable<T> in a class that isn't
literally an enumeration itself, but which owns or otherwise is
associated with an enumeration).

But I also note that a) XmlNode in .NET was not upgraded with the advent
of generics to implement IEnumerable<XmlNode> (it does implement
IEnumerable though), as well as the fact that the newer XNode (or even
XContainer) type in System.Xml.Linq does _not_ implement either
enumeration interface.

This, in spite of the fact that LINQ is _all_ about enumerations and
System.Xml.Linq exists to support a LINQ-style approach to dealing with XML.

This suggests to me that while the original design of XmlNode was
informed by practicality but not necessarily good OOP design practices,
when it came time to designing the all-new System.Xml.Linq types, more
thought to the basic OOP concepts was being done, and they refrained
from the temptation of a potentially awkward inheritance design, opting
rather for a better OOP approach to the classes.

I wouldn't say it's a fatal flaw for a class to implement an interface
that strictly speaking it's not really "is a" rather than "has a", but I
would say it's not the best approach to a clean OOP design.

After all, consider:

class Person : IEnumerable<Person>, IEnumerable<Girl>,
IEnumerable<Boy>, IEnumerable<Car>, IEnumerable<House>
{
private List<Person> _children;

public IEnumerator<Person> GetEnumerator()
{
return _children.GetEnumerator();
}

public IEnumerator<Girl> GetEnumerator()
{
return _children.GetEnumerator()
.Where(child => child is Girl);
}

public IEnumerator<Boy> GetEnumerator()
{
return _children.GetEnumerator()
.Where(child => child is Boy);
}
}

If we allow IEnumerable<Person> as a legitimate interface for Person to
implement, then why not subsets of IEnumerable<Person> describing the
commonly used divisions of children? Why not other enumerations of
other things that a Person might _have_ rather than just what a Person
_is_? Where do you draw the line?

I agree that at times, pure OOP practices aren't the last word in type
design. But when one deviates from pure OOP practices in the
furtherance of some practical matter, one ought to at least be cognizant
that that's what they are doing, rather than trying to rationalize the
deviant design in terms of pure OOP practices.

IMHO, that will result in a much better type design than if one is
telling oneself that they are in fact following good, pure OOP
practices. Once you've rationalized some specific design as good, pure
OOP even though it's not, it becomes a lot easier for the rest of the
type to be poorly design, and to move on to designing other poorly
designed types. By remaining fully aware of when one is breaking the
rules, even if there's a good reason to do so, it remains a lot easier
to continue to follow the rules generally.

Pete
 

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

Top