39

I'm trying to understand the design decision behind this part of the language. I admit i'm very new to it all but this is something which caught me out initially and I was wondering if I'm missing an obvious reason. Consider the following code:

List<int> MyList = new List<int>() { 5, 4, 3, 2, 1 };
int[] MyArray = {5,4,3,2,1};


//Sort the list
MyList.Sort();
//This was an instance method


//Sort the Array
Array.Sort(MyArray);
//This was a static method

Why are they not both implemented in the same way - intuitively to me it would make more sense if they were both instance methods?

BoltClock
  • 630,065
  • 150
  • 1,295
  • 1,284
David Lee
  • 393
  • 3
  • 5

6 Answers6

30

The question is interesting because it reveals details of the .NET type system. Like value types, string and delegate types, array types get special treatment in .NET. The most notable oddish behavior is that you never explicitly declare an array type. The compiler takes care of it for you with ample helpings of the jitter. System.Array is an abstract type, you'll get dedicated array types in the process of writing code. Either by explicitly creating a type[] or by using generic classes that have an array in their base implementation.

In a largish program, having hundreds of array types is not unusual. Which is okay, but there's overhead involved for each type. It is storage required for just the type, not the objects of it. The biggest chunk of it is the so-called 'method table'. In a nutshell, it is a list of pointers to each instance method of the type. Both the class loader and the jitter work together to fill this table. This is commonly known as the 'v-table' but isn't quite a match, the table contains pointers to methods that are both non-virtual and virtual.

You can see where this leads perhaps, the designers were worried about having lots of types with big method tables. So looked for ways to cut down on the overhead.

Array.Sort() was an obvious target.

The same issue is not relevant for generic types. A big nicety of generics, one of many, one method table can handle the method pointers for any type parameter of a reference type.

Hans Passant
  • 873,011
  • 131
  • 1,552
  • 2,371
  • 2
    I've never seen anyone use the word 'jitter' to describe anything other than a morning caffeine high. Are you noun-ing the acronym JIT into JITer (Just-in-time compiler)? – mattmc3 Jul 16 '11 at 00:20
  • 2
    I'm not so sure. Non-virtual methods don't take up room in the method tables (they're only used to support polymorphic dispatch), so switching to a static method isn't needed to save memory. Plus, we're talking about (at worst) a few kilobytes of memory - if that was a concern, they would never have implemented garbage collection. – Bevan Jul 16 '11 at 00:44
  • 6
    @Bevan - Kudos for noting the discrepancy but non-virtual methods do in fact take a slot in the method table. It is an oft quoted difference between C# and Java but it is not in fact true. They are even called with a virtual call, documented in this blog post: http://blogs.msdn.com/b/ericgu/archive/2008/07/02/why-does-c-always-use-callvirt.aspx Also, the table doesn't exist in GC memory, it is stored in the loader heap. It can only be freed by unloading the appdomain. – Hans Passant Jul 16 '11 at 07:55
  • @Hans - Interesting post, thanks for the link. As for GC, my point wasn't that the method table was subject to GC, but that the runtime wouldn't make use of GC at all if a few kilobytes of extra metadata was a concern. – Bevan Jul 16 '11 at 08:44
5

You are comparing two different types of 'object containers':

MyList is a generic collection of type List, a wrapper class, of type int, where the List<T> represents a strongly typed list of objects. The List class itself provides methods to search, sort, and manipulate its contained objects.

MyArray is a basic data structure of type Array. The Array does not provide the same rich set of methods as the List. Arrays can at the same time be single-dimensional, multidimensional or jagged, whilst Lists out of the box only are single-dimensional.

Take a look at this question, it provides a richer discussion about these data types: Array versus List<T>: When to use which?

Community
  • 1
  • 1
Avada Kedavra
  • 7,575
  • 5
  • 29
  • 46
  • +1: Sorting an array is a more complicated endeavor than sorting a list, which is why `Array.Sort` has *17* overloads, whereas `List.Sort` only has four. – StriplingWarrior Jul 15 '11 at 23:32
  • 2
    @StriplingWarrior: Actually sorting both could/would use *exactly* the same code... – BlueRaja - Danny Pflughoeft Jul 16 '11 at 00:07
  • 2
    @StriplingWarrior `List.Sort` just calls `Array.Sort` internally – Magnus Jul 16 '11 at 00:11
  • Well, Arrays "can be jagged" in the same sense as you can have a `List>`. – Random832 Jul 16 '11 at 04:41
  • @Magnus, @BlueRaja - Danny Pflughoeft: Sorry, I didn't mean to indicate that doing a traditional sort on a one-dimensional array is in itself any different than doing the same sort on an array list. Rather, there are a lot more options when you're looking at sorting an array, due to things like the multidimensionality, etc. The idea of "sorting" an array can mean different things depending on circumstances, whereas it's pretty much immediately clear what you mean when you want to sort a list. – StriplingWarrior Jul 17 '11 at 16:14
3

This likely has to do with inheritance. The Array class cannot be manually derived from. But oddly, you can declare an array of anything at all and get an instance of System.Array that is strongly typed, even before generics allowed you to have strongly typed collections. Array seems to be one of those magic parts of the framework.

Also notice that none of the instance methods provided on an array massively modify the array. SetValue() seems to be the only one that changes anything. The Array class itself provides many static methods that can change the content of the array, like Reverse() and Sort(). Not sure if that's significant - maybe someone here can give some background as to why that's the case.

In contrast, List<T> (which wasn't around in the 1.0 framework days) and classes like ArrayList (which was around back then) are just run-of-the mill classes with no special meaning within the framework. They provide a common .Sort() instance method so that when you inherited from these classes, you'd get that functionality or could override it.

However, these kinds of sort methods have gone out of vogue anyway as extension methods like Linq's .OrderBy() style sorting have become the next evolution. You can query and sort arrays and Lists and any other enumerable object with the same mechanism now, which is really, really nice.

-- EDIT --

The other, more cynical answer may just be - that's how Java did it so Microsoft did it the same way in the 1.0 version of the framework since at that time they were busy playing catch-up.

mattmc3
  • 15,986
  • 5
  • 75
  • 96
3

Without asking someone who was involved in the design of the original platform it's hard to know. But, here's my guess.

In older languages, like C, arrays are dumb data structures - they have no code of their own. Instead, they're manipulated by outside methods. As you move into an Object oriented framework, the closest equivilent is a dumb object (with minimal methods) manipulated by static methods.

So, my guess is that the implementation of .NET Arrays is more a symptom of C style thinking in the early days of development than anything else.

Bevan
  • 40,925
  • 10
  • 77
  • 128
2

One reason might be because Array.Sort was designed in .NET 1.0, which had no generics.

John Saunders
  • 157,405
  • 24
  • 229
  • 388
0

I'm not sure, but I'm thinking maybe just so that arrays are as close to Primitives as they can be.

Paul
  • 130,653
  • 24
  • 259
  • 248
  • @Ed S. Seriously? What can you call on an int[] array? As in: int[] nums = new int[3]; ... nums.someMethod(...)? – Jeremy Jul 15 '11 at 22:54
  • 6
    @Jeremy: Besides the static methods of the `Array` class, arrays themselves implement a whole host of interfaces. See http://msdn.microsoft.com/en-us/library/system.array.aspx and http://msdn.microsoft.com/en-us/library/system.array_methods.aspx – BoltClock Jul 15 '11 at 22:59
  • 3
    @Jeremy: you can call `Clone`, `CopyTo`, down to `SetValue`. – John Saunders Jul 15 '11 at 23:28