The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

I know this is wrong, but not why?

I am working on a ecological simulation that models animal behavior patterns depending on the landscape they encounter in their travels. This is being developed in C# .NET 1.1.  So I have a collection class I will call Animals which has an array of the animal class objects inside.

Why would it be bad to have my collection class Animals inherit from the built in System.Array class instead of having the array inside the class.  It feels wrong as heck, but I am clueless on why this is.

As you can tell I am newbie to all this so please excuse me if this seems trivial.  But to me, I want to understand this.
Bob Cummings Send private email
Wednesday, June 13, 2007
Liskov substitution principle.  Loosely, if B derives from (or implements) A, then it should be sensible to use B anywhere you'd use an A.
Wednesday, June 13, 2007
Exactly so. The specific way in which your array-of-Animals violates the interface of System.Array is that you can't store arbitrary objects in it. See also , "Is an array of Derived a kind-of array of Base?".

The Liskov Substitution Principle is one of the most important things that most OO developers miss. The fact that both the Java and .NET class libraries violate it left and right does not help. The fact that inheriting from System.Array felt wrong to the OP is encouraging.

If using .NET 2.0 is not an option, I would have the array-of-Animal class implement IEnumerable at the very least, and probably ICollection as well. That will let you use it in a lot of places that want something like an array, most importantly foreach loops. That's about as far as you can go without violating the LSP.
Wednesday, June 13, 2007
One major advantage of not inheriting from Array is that it gives you the flexibility of swapping out the Array class for some other collection class if it turns out that Array wasn't the best choice. 

In the computer science world, there's a wide variety of data structures for storing a collection of items.  Each has its advantages and disadvantages and it's very common to change your mind on which structure is best for your case.  By deriving directly from Array, you're strongly coupling your Animals class to that concrete implementation so it might be harder in the future to replace it.
SomeBody Send private email
Thursday, June 14, 2007
Something I find myself doing a lot is just using class inheritance for reusing implementation stuff, and then having the client code work with the instances through an interface rather than referring to anything on the concrete implementation class.

For example, in this case I might do something like presenting client code with an IAnimals instance, and having AnimalsImpl inherit from one of the concrete collection class (and implement IAnimals and perhaps other appropriate interfaces).

When I later decide to refactor AnimalsImpl to have the collection as a property instead, or maybe use a different type of collection implementation underneath, or substitute some hardcoded mock collection for testing something, the client code need know nothing of these changes since it only codes against the interface.
Thursday, June 14, 2007
Forgot to mention that I do Java so Im not all that familiar with .NET details but I presume the concept will apply there too?
Thursday, June 14, 2007
> System.Array

Can you really do that in C#?

Anyway, one reason is that you give users the ability to really mess with your animals unchecked by your object. They can add an animal without going through your interface which means you can't fire events, perform other checks, and just generally provide only the animals interface.

An array has the following methods. Are these really animals methods and should they be exposed as animals methods? No and no.

Array.BinarySearch(System.Array, System.Object) Method
Array.BinarySearch(System.Array, int, int, System.Object) Method
Array.BinarySearch(System.Array, System.Object, System.Collections.IComparer) Method
Array.BinarySearch(System.Array, int, int, System.Object, System.Collections.IComparer) Method
Array.Clear Method
Array.Clone Method
Array.Copy(System.Array, System.Array, int) Method
Array.Copy(System.Array, int, System.Array, int, int) Method
Array.CopyTo Method
Array.CreateInstance(System.Type, int) Method
Array.CreateInstance(System.Type, int, int) Method
Array.CreateInstance(System.Type, int, int, int) Method
Array.CreateInstance(System.Type, int[]) Method
Array.CreateInstance(System.Type, int[], int[]) Method
Array.GetEnumerator Method
Array.GetLowerBound Method
Array.GetUpperBound Method
Array.GetValue(int[]) Method
Array.GetValue(int) Method
Array.GetValue(int, int) Method
Array.GetValue(int, int, int) Method
Array.IndexOf(System.Array, System.Object) Method
Array.IndexOf(System.Array, System.Object, int) Method
Array.IndexOf(System.Array, System.Object, int, int) Method
Array.Initialize Method
Array.LastIndexOf(System.Array, System.Object) Method
Array.LastIndexOf(System.Array, System.Object, int) Method
Array.LastIndexOf(System.Array, System.Object, int, int) Method
Array.Reverse(System.Array) Method
Array.Reverse(System.Array, int, int) Method
Array.SetValue(System.Object, int) Method
Array.SetValue(System.Object, int, int) Method
Array.SetValue(System.Object, int, int, int) Method
Array.SetValue(System.Object, int[]) Method
Array.Sort(System.Array) Method
Array.Sort(System.Array, System.Array) Method
Array.Sort(System.Array, int, int) Method
Array.Sort(System.Array, System.Array, int, int) Method
Array.Sort(System.Array, System.Collections.IComparer) Method
Array.Sort(System.Array, System.Array, System.Collections.IComparer) Method
Array.Sort(System.Array, int, int, System.Collections.IComparer) Method
Array.Sort(System.Array, System.Array, int, int, System.Collections.IComparer) Method
Array.System.Collections.IList.Add Method
Array.System.Collections.IList.Clear Method
Array.System.Collections.IList.Contains Method
Array.System.Collections.IList.IndexOf Method
Array.System.Collections.IList.Insert Method
Array.System.Collections.IList.Remove Method
Array.System.Collections.IList.RemoveAt Method

Array Properties

Array.IsFixedSize Property
Array.IsReadOnly Property
Array.IsSynchronized Property
Array.Length Property
Array.LongLength Property
Array.Rank Property
Array.SyncRoot Property
Array.System.Collections.ICollection.Count Property
Array.System.Collections.IList.Item Property
son of parnas
Thursday, June 14, 2007
1. Switch to .NET 2.0.
2. Use System.Collections.Generic.List<Animal>.
Chris Nahr
Thursday, June 14, 2007
+1 for .Net 2 generics - they are really nice.
Thursday, June 14, 2007
Yes, going to .NET 2.0 is recommended so you can use List<Animal>, but this should be encapsulated in an Animals class (or AnimalRepository or whatever) the same way the Array should be, for all the same reasons. You don't want to be slinging List<Animal> all around your code and then discover you really wanted to use a Dictionary, etc. The Animals class will also have nice methods like FindMammals etc.
Mike Stockdale Send private email
Thursday, June 14, 2007
I would like to thank everyone who responded.  I knew it felt wrong, but now I have several concrete reasons. 

After reading all your comments, I kind of feel foolish because they all make so much sense.  I should have seen them myself.  Thanks again.



PS Yes you can inherit directly from System.Array in 1.1 anyhow.
Bob Cummings Send private email
Thursday, June 14, 2007
"but this should be encapsulated in an Animals class "

if by encapsulated you mean derived from then yes.
Tuesday, June 19, 2007
And in today's episode of "how to screw up an object oriented design", we have a special (as in forrest gump special) lesson on the use of "inheritance" and "encapsulation" as if they're synonyms.

Um. Right.

Tuesday, June 19, 2007

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
Powered by FogBugz