Arrays considered somewhat harmful

I got a moral question from an author of programming language textbooks the other day requesting my opinions on whether or not beginner programmers should be taught how to use arrays.

Rather than actually answer that question, I gave him a long list of my opinions about arrays, how I use arrays, how we expect arrays to be used in the future, and so on. This gets a bit long, but like Pascal, I didn't have time to make it shorter. 

Let me start by saying when you definitely should not use arrays, and then wax more philosophical about the future of modern programming and the role of the array in the coming world.

You probably should not return an array as the value of a public method or property, particularly when the information content of the array is logically immutable. Let me give you an example of where we got that horridly wrong in a very visible way in the framework.  If you take a look at the documentation for System.Type, you'll find that just looking at the method descriptions gives one a sense of existential dread. One sees a whole lot of sentences like "Returns an array of Type objects that represent the constraints on the current generic type parameter." Almost every method on System.Type returns an array it seems. 

Now think about how that must be implemented. When you call, say, GetConstructors() on typeof(string), the implementation cannot possibly do this, as sensible as it seems.

public class Type {
   private ConstructorInfo[] ctorInfos;
   public ConstructorInfo[] GetConstructors()
     if (ctorInfos == null) ctorInfos = GoGetConstructorInfosFromMetadata();
     return ctorInfos;

Why? Because now the caller can take that array and replace the contents of it with whatever they please. Returning an array means that you have to make a fresh copy of the array every time you return it. You get called a hundred times, you’d better make a hundred array instances, no matter how large they are. It’s a performance nightmare – particularly if, like me, you are considering using reflection to build a compiler. Do you have any idea how many times a second I try to get type information out of reflection?  Not nearly as many times as I could; every time I do it’s another freakin’ array allocation!

The frameworks designers were not foolish people; unfortunately, we did not have generic types in .NET 1.0. clearly the sensible thing now for GetConstructors() to return is IList<ConstructorInfo>. You can build yourself a nice read-only collection object once, and then just pass out references to it as much as you want.

What is the root cause of this malaise? It is simple to state: The caller is requesting values.  The callee fulfills the request by handing back variables.

An array is a collection of variables. The caller doesn’t want variables, but it’ll take them if that’s the only way to get the values. But in this case, as in most cases, neither the callee nor the caller wants those variables to ever vary. Why on earth is the callee passing back variables then? Variables vary. Therefore, a fresh, different variable must be passed back every time, so that if it does vary, nothing bad happens to anyone else who has requested the same values.

If you are writing such an API, wrap the array in a ReadOnlyCollection<T> and return an IEnumerable<T> or an IList<T> or something, but not an array.  (And of course, do not simply cast the array to IEnumerable<T> and think you’re done!  That is still passing out variables; the caller can simply cast back to array!  Only pass out an array if it is wrapped up by a read-only object.)

That’s the situation at present. What are the implications of array characteristics for the future of programming and programming languages?

Parallelism Problems

The physics aspects of Moore’s so-called “Law” are failing, as they eventually must. Clock speeds have stopped increasing, transistor density has stopped increasing. The laws of thermodynamics and the Uncertainty Principle are seeing to that. But manufacturing costs per chip are still falling, which means that our only hope of Moore’s "Law" continuing to hold over the coming decades is to cram more and more processors into each box. 

We’re going to need programming languages that allow mere mortals to write code that is parallelizable to multiple cores.

Side-effecting change is the enemy of parallelization. Parallelizing in a world with observable side effects means locks, and locks means choosing between implementing lock ordering and dealing with random crashes or deadlocks. Lock ordering requires global knowledge of the program. Programs are becoming increasingly complex, to the point where one person cannot reasonably and confidently have global knowledge. Indeed, we prefer programming languages to have the property that programs in them can be understood by understanding one part at a time, not having to swallow the whole thing in one gulp.

Therefore we tools providers need to create ways for people to program effectively without causing observable side effects.

Of all the sort of “basic” types, arrays most strongly work against this goal. An array’s whole purpose is to be a mass of mutable state. Mutable state is hard for both humans and compilers to reason about. It will be hard for us to write compilers in the future that generate performant multi-core programs if developers use a lot of arrays.

Now, one might reasonably point out that List<T> is a mass of mutable state too. But at least one could create a threadsafe list class, or an immutable list class, or a list class that has transactional integrity, or uses some form of isolation or whatever. We have an extensibility model for lists because lists are classes. We have no ability to make an “immutable array”. Arrays are what they are and they’re never going to change.

Conceptual Problems

We want C# to be a language in which one can draw a line between code that implements a mechanism and code that implements a policy.

The “C” programming language is all about mechanisms. It lays bare almost exactly what the processor is actually doing, providing only the thinnest abstraction over the memory model. And though we want you to be able to write programs like that in C#, most of the time people should be writing code in the “policy” realm. That is, code that emphasizes what the code is supposed to do, not how it does it.

Coding which is more declarative than imperative, coding which avoids side effects, coding which emphasizes algorithms and purposes over mechanisms, that kind of coding is the future in a world of parallelism. (And you’ll note that LINQ is designed to be declarative, strongly abstract away from mechanisms, and be free of side effects.)

Arrays work against all of these factors. Arrays demand imperative code, arrays are all about side effects, arrays make you write code which emphasizes how the code works, not what the code is doing or why it is doing it. Arrays make optimizing for things like “swapping two values” easy, but destroy the larger ability to optimize for parallelism.

Practical Problems

And finally, given that arrays are mutable by design, the way an array restricts that mutability is deeply weird. All the contents of the collection are mutable, but the size is fixed.  What is up with that? Does that solve a problem anyone actually has?

For this reason alone I do almost no programming with arrays anymore. Arrays simply do not model any problem that I have at all well – I rarely need a collection which has the rather contradictory properties of being completely mutable, and at the same time, fixed in size. If I want to mutate a collection it is almost always to add something to it or remove something from it, not to change what value an index maps to.

We have a class or interface for everything I need. If I need a sequence I’ll use IEnumerable<T>, if I need a mapping from contiguous numbers to data I’ll use a List<T>, if I need a mapping across arbitrary data I’ll use a Dictionary<K,V>, if I need a set I’ll use a HashSet<T>. I simply don’t need arrays for anything, so I almost never use them. They don’t solve a problem I have better than the other tools at my disposal.

Pedagogic Problems

It is important that beginning programmers understand arrays; it is an important and widely used concept. But it is also important to me that they understand the weaknesses and shortcomings of arrays. In almost every case, there is a better tool to use than an array.

The difficulty is, pedagogically, that it is hard to discuss the merits of those tools without already having down concepts like classes, interfaces, generics, asymptotic performance, query expressions, and so on. It’s a hard problem for the writer and for the teacher. Fortunately, for me, it's not a problem that I personally have to solve.

Comments (63)
  1. Georgi says:

    Very interesting point of view!

    Your arguments against arrays sound very strong and I personally agree with them.

    It will be interesting if there is anyone who can advocate poor arrays 🙂

  2. Instead of  GetConstructors() returning IList<ConstructorInfo>, I would prefer the framework actually define a readonly list interface such is IReadOnlyList<T> and return an instance of that.  Returning IList<T> for a readonly list is a bad idea because you’re not actually returning an IList<T>.  You’re returning an object that is kind of an IList<T> since it can’t fulfull several of the methods.  

  3. Jonathan Allen says:

    Though probably not what want. IEnumerable<T> is effectively a read-only list.

  4. Jeff says:

    How strange, I was tackling this very issue myself just this afternoon. I wanted to use the array because the code DOM serializer can persist them in nice ways, however, I was aware of the mutable nature of their contents. I managed to solve my serializer problem by having a constructor take IEnumerable<string>, provide the array to consumers as a read-only IList<string> property, and have my type converter wrap the IList in a List<string> and use ToArray with an instance descriptor to my IEnumerable<string> constructor. This way the code DOM serializer persists nicely (rather than persist an IEnumerable which it insists on handling as a resource blob), but my constructor supports more collections and my array contents are immutable for the lifetime of the constructed object.

    Of course, I could’ve worked on writing a nicer serializer, but this route was simpler.

    Having been caught out by arrays in many of the ways you mention, I whole-heartedly concur with you.

  5. @Jonathan,

    It’s more of a sequence than a list though.  List’s have several properties that set them apart from sequences.  Namely O(1) random access and O(1) size calculation.  In this situation we’re converting from an array to a new data structure.  It seems more natural to go with a list since we already have all of the elements grouped together.

    Then again, if reflection could be done more efficiently "on demand" then a sequence would potentially be better.  

  6. I like how you bring the topic of arrays back into the more general topic of mutable data.  I’ve been writing lots of Python the last two years, and over that time my style has morphed into almost exclusivly using immutable types.  Most of the time, I even use a tuple as a collection instead of an array simple because it’s immutable.  Clearly, a library writer cannot safely pass out references to internal mutable data.

    I also like how you steer the topic of mutability into the topic of concurrency since, as you describe, they are so closely related.  Again, I’ve found that over the last few years my style of programming has morphed, not just from mutable data to immutable data, but from thread-based concurrnecy to actor-based concurrency.  

    You describe a good solution for C# to address readonly/immutable data, but I’ve yet to see a good solution in C# for concurrency.  Of course, if you addressed THAT in this post, it would have become quite a long post!  Still, I’m very curious to see what future versions of C# do to address concurrency. It’s an incredibly important topic and no one except the Erlang people seem to have taken it head-on, and everyone seems to think they are crazy for one reason or anothoer.  

    Will we be seeing a "threads considered somewhat harmful" post soon?

  7. danyel says:

    arrays are good for image processing and science applications: each cell represents a physical object or an atom or a pixel. for images, the size really is fixed but the pixels change.

    that said, I don’t know of other places where they are a good model, and your article is generally spot on.

  8. Thomas says:

    The problem with returning arrays from methods is actually a subset of a more general problem: returning references to private data. The very same argument you make against returning arrays can also be made against returning another object.

    Also, I don’t think that it is bad to return an array casted to IEnumerable<T>. You argue that the caller can simply cast it back — true. But even if we wrap it in another object, the caller can still access it; if not through reflection, then through unsafe memory operations or whatever. If the caller insists on breaking your code, he will be able to do so regardless.

  9. Jon Davis says:

    I like arrays for some things. For example, String.Split(). I use that frequently, and then I modify the contents of individual indexes frequently. If Split() returned ReadOnlyCollection<string> I’d end up converting that to a string array, frequently.

    Likewise, any time you’re working with fixed-length linear data, arrays are appropriate.

    However, I fully agree with the occasional scenario where arrays were used only because generics weren’t available, such as in the scenario you demonstrated with, which quite honestly System.Reflection is one of few places I’ve ever been really annoyed that .net gave me an array. That said, my reasons were quite the opposite from yours. I wanted *more* mutability. For example, GetProperties returns an array and say I wanted to loop through the list and remove the items that didn’t match certain criteria, such as checking for certain custom attributes. In both cases of ReadOnllyCollection<PropertyInfo> and PropertyInfo[], I have to convert to a List<PropertyInfo> to do that. Quite a pain.

    So in other words, no one can be happy.

  10. I completely agree with Jared.

    Having an interface that is essentially IEnumerable<T>+this[int] {get;} (IIndexedEnumerable?) woud be the best solution for this problem. Also this interface would solve the future problem of result variance.

  11. Chris Nahr says:

    Surely this issue would be best addressed by adding a read-only array at the CLR level, or even better a recursive read-only tag for arbitrary types?  Then we could have C++ style const-ness as well…

  12. Anders Borum says:

    I second the request for an expanded interface for read only collections (but perhaps we should take this to the BCL team instead).

    The more I read on this blog, the more I’m looking forward to PDC. Keep them coming Eric!

  13. Superb post. Thanks for that. Story of Engineering. The very foundations and thought asssumptions can crumble at any time. It is ironic how unsuited Arrays are for anything. Most of the time I use arrays in situations where I mean "Block of information for you to look at, not touch it". Indeed that construct is utterly unsuited.

    Will it not be possible in the future to state that an array should be read-only? Or is it impossible for some known unknown ? Or is it even a silly question because I still don’t get it? 😉

  14. To Jon Davis:

    If you need to apply a certain criteria on the list content, you should apply a predicate on it (i.e. myList.Where(…)).

    In general, if you need to change the [object] stream content, produce a new stream with correct content. This will comply with goals of this article. Basically that’s what LINQ does.


  15. Paul Hill says:

    My fingers are crossed that CLR embraces Const at some point in the future.  Const arrays the enforce immutability at compile-time would be wonderful.

  16. Care to share the details of "…considering using reflection to build a compiler…"?

  17. Software Engineer says:

    ReadOnlyCollection<T> return references to object.  The object’s members can be changed.  We just can’t add, remove or change a reference to the ReadOnlyCollection.  So returning this collection still does not guarantee 100% readonly collection

  18. Software Enginner says:

    I mean Add, Remove or change the reference of objects already inside the collection.

  19. David Nelson says:


    As I’m sure Eric would say (because he has so many times before), you cannot stop someone accessing private data if they have full security access; in that case you have to assume that they have access to all of the memory in the process. What matters is protecting data that is being passed to code that does NOT have full security access, in particular code that cannot use reflection. In that case, accessing private data inside your class would not be possible, but casting your return value from an IEnumerable to an array would be perfectly legal, and would give that untrusted code mutable access to your private data.

  20. aaronla says:


    The CLR doesn’t have a comprehensive ‘const’ semantic like C++, and in order to maintain interoperability with other programming languages, including C#, it probably never will.  

    That said, you can take and appy attributes to just about everything, including return values.  You can invent ‘const’, or use an existing attribute for that purpose.  You could then extend each programming language to require it, and add runtime checks on the IL of callers to ensure they don’t perform non-const modifications to const return values, references, and argumenst.  And you could extend existing languaged — writing a C# compiler that issues errors if you violate const correctness.  

    But that’s a lot of work.


    I appreciate that you’d like to return read-only-proxies in many cases instead of arrays, especially in ‘getters’.  But Joe Duffy pointed out at (link) that proxies, such as enumerators, are often more expensive than they seem on the current JITter, more expensive than such proxies are in compiled languages (i’m thinking of vector::const_iterator, for instance).  

    “In almost every case, there is a better tool to use than an array” — i’d agree.  It’s unfortunate that there’s a perf penalty to those better tools, but often it can be justified by the benifits (in product reliability, reduced development costs, bugs found earlier) of proxies.


  21. Eric Lippert says:

    Indeed. Attributes are the best you can do in C#. If you were writing your own language what you’d probably want to do is use an optional type modifier rather than an attribute; in C++, adding "constness" changes the _signature_ of a method.  In the CLR, adding an attribute does not change a signature but adding an optional type modifier does. (This is how managed C++ does constness.)

  22. Eric Lippert says:

    > Care to share the details of "…considering using reflection to build a compiler…"?


    csc foo.cs /r:bar.dll

    Somehow the compiler has to get type information out of bar.dll in order to compile foo.cs.  Reflection seems like a good candidate.  Today the compiler uses the unmanaged metadata reader interfaces, but I would like to write any new tools we come up with in C#, which means that suddenly System.Reflection becomes a reasonable choice. Not the only choice, but a reasonable one.

  23. RussellH says:

    “transistor density has stopped increasing”

    Do you mean will stop increasing in the future?  Aren’t Intel and AMD are both talking about new process generations with higher transistor density.  For instance: (link) and (link)

    45 nm is now shipping and 32nm and 22nm are both planned.

    On the issue of arrays, their use can dramatically increase performance in multi-processor, shared memory architectures.  They give you locality.  You allocate them all at once, so the memory is contiguous.  This means cache hits are far more likely with array access.

    If you are designing producer/consumer queues in C++, you can align the queues to start on a processor cache line, and control the enqueue and dequeue processes such that the cache lines do not “ping pong” between processors.  So yes, that solves a problem that I had.

    Arrays are generally preferred over linked structures when performance is a concern.

    Here is a typical reference from processor optimization manual:

    “As you can see, traversing an array gives the processor ample opportunity for concurrency in generating memory requests. Overlapping memory operations results in lower effective latency per item. In contrast, traversing a linked list is fundamentally sequential. The penalty is especially bad when the array elements are randomly scattered in memory: the full memory latency cost is incurred for accessing each individual item.

    The simple conclusion is that arrays should be preferred over linked lists, when they are capable of doing what’s needed. This is especially true when the data will typically be accessed in a sequential manner.”

    What I’m saying is that I’ve found arrays to be a critical tool to solve performance issues and of course you have to be careful to use them correctly.

  24. Eric Lippert says:

    OK, so lets suppose that transistor density in the very highest end machines quadruples in the next generation. Does anyone seriously believe that it will ever quadruple again? Maybe density is still increasing, but the end is nigh.

    And as for performance — sure, there are plenty of applications where performance is gated on minimizing cache misses. If careful testing of your program against user-focused metrics indicates that cache misses are your hot spot AND your performance is unacceptable then sure, consider using an array.  But understand that doing so comes with costs of its own, namely, having a whole pile of mutable state which must be carefully protected from misuse.

  25. kostat says:


    If you need minimize cache misses, usually it’s enough back your IList by an array – this will bring in the needed memory management optimization without sacrificing the interface elegance.


  26. Aaron G says:

    I know this wasn’t the focus of your post, but doesn’t Moore’s Law often taper off from time to time, only to kick back into action via some massive technological leap?  It happened with transistors coming from vacuum tubes, and it’ll probably happen again with one of the newer areas of research, like quantum chips or DNA or whatever.  Maybe in the literal sense, transistor density won’t continue to increase forever, but computing power in general probably will, and not just through the addition of more cores.

    On topic: as others have commented, it seems that 9 times out of 10, what I really need is a read-only, indexed sequence.  I always think, hey, let’s make things as general as possible by using an IEnumerable<T>, and then realize later on that I need indexed access, and have to change it to an IList<T>, which never feels quite right because its "immutability" is just in the implementation.  And using an actual ReadOnlyCollection<T> instance never feels quite right either, I don’t know why.

    ‘Course I realized while writing this that it would be trivially easy to write an IReadOnlyList<T>, a wrapper class, and a couple of extension methods for conversion; don’t know why this never occurred to me before.  Maybe because it’s a stupid idea and I haven’t yet realized *that*. 🙂

  27. Eric Lippert says:

    Moore’s Law is badly named. It really ought to be "Moore’s Observation"; just because a particular economic trend has held for a few years does not make it a law of nature.

    It is the case that every time a particular technology has been tapped out, a new technology has come along to replace it.

    Similarly, every time we’ve gotten close to running out of oil, either new reserves have been discovered, or new technologies for extending existing reserves have been found.  

    It might well be the case that future technologies open up massive new vistas in cheap computational power. And it might be the case that all the oil we’ll ever need is available for cheap in some place that we’ve not looked for it yet.

    But there is no law of physics that is going ensure that either case comes to pass, and it would therefore be unwise to assume that this will happen. If new magical technologies are invented, great. I’m pro that. But I’m going to make the conservative assumption that refinements of old technology are what we’ve got to work with now and going forward.  

    Or, look at it another way. I cannot possibly design tools for an unknown future that is radically different from today. I could guess, and likely be wrong, or I could design tools for the most likely future.

  28. Eric Lippert says:

    > Will we be seeing a "threads considered somewhat harmful" post soon?

    No, because I already wrote it in 2004:

  29. RussellH says:

    I was probably overreacting, or focusing on "using" an array vs. "handing out" an array.  I guess StringBuilder is a decent example of encapsulating an array in a useful way.

    @Aaron G:

    When I was in graduate school in the 1991-1992 time frame, optical computing was supposed the next big thing.  No one (at least not my professors) thought CMOS technology would get as far as it has.  I’m not disagreeing with Eric.  Clearly, the trend now is in the direction of more and more cores (threads) per processor with constant or decreasing throughput per thread.

  30. Ree says:

    Who says arrays must be mutable? The point is mute if they are not.

    Apart from C# being so deficient with constness (which no matter what you do at runtime will never bring the point back home: compile-time checks and optimisations that are slowly catching up in compilers), it is very deficient with poor-man sequence abstraction.

    There is no way to do reverse iteration, there is ugliness of ReadOnlyCollection, there are huge, huge perf hits across the board because ‘managed’ brings ‘overhead’. There are hacks on foreach compilation time and time again, there are hacks on generic lists in VM implementation and IL.

    Seems to me the entire posts has gone off on the tangent of critising something CLR adopted in memory management only to lose itself in another area of non-coherency.

    Proper sequences (compile-time, meta-programming and more), and vectors are brilliant, mutable or not. Arrays are just a representation you can swap however you wish.

    That is the real problem, the CLR, not the array type.

  31. Ree says:

    While here, the ‘idioms’ you mentioned for C#, they are more deficient that people are willing to admit. Here we are again fighting the runtime against something we losing control over. So wait for VM to catch up?

    I am in complete agreement with russelh and especially on that long and trivial readlines example, two blog entries back. That classic against an entire lecture in complication and IEnumerable not cutting it with all the candy:

    while ((line = reader.ReadLine()) != null)

    simply does it, and no idiom of C# can do it more elegant. If you take it into proper sequence world:

    while ( std::getline …  or

    cont<T> sequence( (std::istream_iterator< T >( T ) ), std::istream_iterator< T >() );

    Than you can even reverse it in one liner: std::reverse, transform it into anything, and do all that with any type or anything at COMPILE-TIME.. Whoaa, C# looks like 1960s tech in comparison.

    There is some serious compile-time problems, that move into runtime, then there are patches to compilers, and finally we get LINQ. The problem is that LINQ code is around 50% slower than simply generic lists, and lists are slower than arrays and so it goes on an on.

    The lesson I learned 20 years back is that if something isn’t optimal, it isn’t the type, it is the tech or abstraction over it causing the problem, usually a performance and in this instance it is a clear, inferior semantic confusion of ‘sequence’ in CLR.

  32. James S. says:

    Aren’t arrays actually quite good when it comes to parallelism? They’re really easy to divide into chunks processed by different threads, unlike linear data structures such as lists. As you point out, they’re not mutable (only the elements are mutable), which helps there (or rather, it doesn’t hurt). Your comments about metadata are also shifting the blame for CLI’s lack of an equivalent to const& onto arrays, which hardly seems fair. On the other hand, I think you’ve ignored some of the *actual* pedagogical problems such as jagged vs. rectangular arrays.

    In the spirit of "considered harmful", I consider your considerations harmful!

  33. I think you forget to mention another, more important, point: having a readonly collection of references to objects won’t save you from modifying objects.

    Thus IList<T> won’t solve the problem you’re mentioning!

    You either have to copy all objects (or use value types), or wrap all objects your array or collection contains, in a "readonlifier" wrapper.

    But the best thing is to design your objects (and it doesn’t matter if you return them as items of an array or an collection) so that you have different interfaces for different uses.

    And C++’s const array modifier perfectly solves the problem you’re mentioning.

    My 5c, I might be too sleepy to miss the whole point 🙂

    (I’ve recently replaced LINQ queries with direct array addressing in array to get 5x performance boost. At the same time the interface between the algorithm and the data store has remained the same. But I with all hands for your arguments regarding paralellization. Just arrays is not the key reason of why some algorithms are hard to parallel)

  34. Mark Rendle says:

    Developers in my team are encouraged (with threats of violence) to return interface types wherever possible, using the minimum interface required by the consumer, e.g. IEnumerable<T> if iteration is required, or IList<T> if indexed access is necessary.

    Ree: With the aforementioned move into many-core processors, the ability to parallelize is becoming more important than single-thread performance, and this is where LINQ will come into its own, especially with the PFX extensions.

    Roman: ConstructorInfo is an immutable class, in which instance the example is valid. Personally, I tend toward immutable classes for everything except business objects.

    And as for Moore’s Law: what about memristors?

  35. jcoehoorn says:

    "It is important that beginning programmers understand arrays;"

    It seems to me that one of the main reasons for this was so that they could then quickly understand strings.  But that day is long gone.  In a world where strings are now first class citizens of their own, it should be possible to leave arrays as a concept to be introduced at the same time as other more appropriate collections.

  36. It’s much more important to understand the difference between O(1) and O(n), I agree 🙂

  37. In this carnival there&#39;re a lot of software design/patterns and frameworks a bit of SOA, UML, DSL

  38. Keith Farmer says:

    @danyel:  That may be, but in that case you’re still talking about something that should be wrapped in something like an Image class, and not exposed to public view.

    @ree:  It is generally more important to have code that is more maintainable and more amenable to reason than it is to have code that is more performant.  The fastest code serves no purpose if it’s simply the fastest to produce an incorrect result, or the fastest to befuddle.  I’ll take the CLR’s abstractions any day.

  39. David Nelson says:


    Part of Ree’s point was that, if the CLR supported const and non-mutable arrays, you wouldn’t need an abstraction to expose array-like data, and you could have the best of both worlds, maintainability and performance. Which is a perfectly valid point. Whether the gains from supporting const and immutability in the CLR would be worth the effort is another question entirely.

  40. Matt Neerincx says:

    I say CLR devs hate arrays because CLR does not efficiently deal with arrays.   Also, CLR memory management makes using arrays inefficient.

    Ok, simple example.   A string.

    In a language like C++, a string is an array of chars.   Why is array of chars so handy?  Because I can modify the chars inside the array and avoid HUGE performance costs of creating new strings over and over and over when doing inline textual processing.

    I wrote a simple app to process newsgroup posts and push them into SQL Server in C#.  Due to string manipulations, I was burning huge amounts of CPU in GC collecting strings and StringBuilders.

    In C++, I could read the data from NNTP directly into a byte array, then rip through the byte array and do fixups and scan for bad things, and in some cases where there were no fixups pass the byte array directly to SQL Server for upload.  Zero allocs, zero memcpys in primary code path.

    Eventually I redesigned my C# code to do the same thing but I was painfully difficult to do.  You can’t just cast a byte array to char * in C#.

    Overall the design compromises the CLR made are sensible.  These design choices have handicapped arrays in C#, let’s be honest about this at least.  In C++ char arrays have probably caused 10,000 more huge horrible disasters than they have solved.

  41. minister says:

    Most of the generic collections dealing in atomic list-type structures internally use arrays (with the exception of SortedDictionary, which uses a tree, and LinkedList, which deals with references to succeeding and preceding LinkedListNodes, and a few others). Now, unless you specify (if you are able to) an initial capacity, adding items dynamically, whether using Add() or the indexing property of the collection you are using, will trigger an allocation of a new array, and an Array.Copy(), when the item you are currently attempting to add would result in a new size that exceeds the current internal size of the collection. This can affect performance. However, what’s even worse is that all of the adding/setting mechanisms in these collections trigger a check to determine whether the item is already in the internal array (usually using a binary search). Furthermore, this check forces invocations of methods in helper classes that aid in comparison and equality-calculations – this process results in pushing classes and methods onto the call stack. A lot of overhead, and ALL of these contribute to performance strain.

    If I have a collection and know certain things at runtime, such as how big it will be, that items I’m adding are new, etc., I choose an array to avoid all the performance stresses and overhead. I like to have a great granularity of control over how I deal in collections, so although I do agree with most of your points, I’d still be hard-pressed to pick a List over an array when I don’t need to do more than basic array manipulation.

    On another topics about arrays, I rreally wish that the framework would allow us to be able to create an array with all elements initialized to a particular value of our choosing at creation time. For example, if I want an array of, say, 100 bools, where all elements should be set to true, I have to instantiate the array, then initialize it with a loop; it would be really helpful to just be able to write "bool[] arr = new bool[100](true);", or something like that.

  42. Rod Ghioto says:

    I am an "engineer" engineer who has been writing water resources simulation software over a 30-year career.  I have moved through every operating system that MS has deployed and nearly every language (Fortran, Basic, Pascal, C, C++ and C#) striving to overcome every less efficient improvement that has been placed in its OSs and revisions to compilers.  MFC was a 5-year trip.  Now, with managed memory and all of the good things that have been done to protect me and my users from myself, I have concluded that MS has basically abandoned the scientific community in areas where speed is important.  Arguments made for distributed (team) development and tool development are well taken.  However, people who have high performance needs that arrays used to provide are basically out of luck.

  43. Tim Gordon says:

    I agree, Eric, that "completely mutable, and at the same time, fixed in size" is not often a useful combination.

    However, an immutable array (of, typically, immutable objects) is often precisely what I want, especially where performance is an issue.

    In such cases, the following works:

    struct ConstArray<T>


    public ConstArray(T[] values) { this.values = values; }

    public T this[int index] { get { return values[index]; } }

    public int Length { get { return values.Length; } }

    T[] values;


    (It would be even better if the jitter could optimise index access in loops as it does for system arrays.)

    BTW, here’s yet another (forlorn, I know) plea for the C++ const modifier, which, as has been pointed out, would fix this issue.

  44. Would an empty array be safe to return?

  45. Very recently on a project, I was having significant issues with System.IO.Directory.GetFiles, in which

  46. Brad Dodson says:

    In general I’m beginning to come to this view. Arrays don’t express programmer intent in the fast majority of cases.

    Is there any chance that array variance could get fixed in future versions of the framework? My understanding is that becuase of it, the runtime has to type check all array operations. I could see this being a huge win in the cases that I really need an array (like image manipulation), and for all of the framework classes that are using arrays under the hood (such as List<T> I presume). Perhaps the JIT is already smart enough to avoid the penalty in most cases.

  47. Mikkel Christensen says:

    Just pointing out that the C++ const modifier is an illusion – it does not solve any issues regarding immutability whatsoever, courtesy of const_cast<>. So if the CLR team ever decides to add a const modifier, I’m hoping that they will not make the same mistake that the C++ standards committe did…

  48. Jay Bazuzi says:

    I was just noticing that arrays get nice syntax help in C#:

               var a = new[] { 1, 2 };    

               int[] b = { 1, 2 };        

    while other collections have to work a little harder:

               var c = new Dictionary<string, int> { {"a", 1}, {"b", 2} };     // OK

               Dictionary<string, int> d = { { "a", 1 }, { "b", 2 } };         // error CS0622: Can only use array initializer expressions to assign to array types. Try using a new expression instead.

    Too bad.

    Hey, PowerShell can do it:

       $myHash = @{ "a" = 1; "b" = 2 }

  49. @Jay

    F# can do it succintly as well

    let d = [("a",1);("b",2)] |> Map.of_list

  50. X says:

    Your comments do not apply to value types, so as long as it is an array of say int, string, KeyValuePair<TKey, TValue> we are fine.

  51. Jimmy Bogard says:

    A while back, Eric Lippert talked about arrays being somewhat harmful .&#160; The reason being, if you

  52. Moblog says:

    QUOTE:You probably should not return an array as the value of a public method or property, particularly when the information content of the array is logically immutable. Let me give you an example of where we got that horridly wrong in a very visible

  53. Tim Long says:

    A bit of light reading while you digest your turkey sandwiches… Fabulous Adventures In Coding : Arrays

  54. Sander Pool says:

    Interesting discussion. As someone who moved from Algol 68 to Pascal to C to C++ to VB6 to VB.NET to Perl to Ruby to C++ with CLR I think I’ve seen a few programming paradigms in my time. I’ve also seen my share of dogma ‘thou shalt not do this’ or ‘do this or else’. Dogma is dangerous in real life and while programming. The important thing is to understand why certain mechanisms are ‘good’ or ‘bad’ or even ‘dangerous’ and then decide what’s appropriate for your application. As I’m sure you all do I try to use the right tool for the job. A quick test script that needs to run on Windows and Linux is easily written in Ruby. A telescope control program that wakes up every second to see if a new event needs to be recorded works well with VB.NET. Now I’m working on astronomical image processing software. This software needs to zip through images consisting of millions of floats or ints. I use C++ for that with classes that hide mapping from col/row coordinates to array indexes. Because I use inline classes I get the benefit of immutability of the array and encapsulation in general while still maintaining a semblance of performance. Another poster mentioned that dividing arrays in sections makes good sense for multi-core optimization. I agree with this, for my application anyway. Divide and conquer strategies will work well in this case.

    Anyway, I’m not ready yet to give up on arrays for storing large amounts of sequential data. It seems silly to store 6 million pixel values in a linked list. But it does make sense to protect that chunk of data with a class that can be unit tested.

  55. Jeff Lorenzini says:

    I find in c# I only use arrays for speed. I use them for cross-referencing data, or anywhere performance is important.

    Before I read this blog entry I was asking a colleague, does anybody use arrays in c#? Because you’re right, there’s usually better tools available for what you’re trying to do.

  56. Thomas Brown says:

    @Rod: I feel your pain, having been involved in the design and development of scientific, DSP software from back in the 80’s.

    I appreciate C# and .NET and the managed framework for a lot of things and I do feel that it’s easier to develop applications now than it was back in MFC days and certainly than in the Good Ol’ Win16 days.

    But there are application domains where an array is simply the best structure to hold large amounts of data for processing.  I cannot imagine working with any kind of DSP problem, e.g. signal smoothing, peak detection and integration for scientific analysis; numerical analysis, or low-level high-performance graphics where manipulating the frame buffer(s) is critical, without using arrays.

    That said, all of the points brought out seem valid to me and I’ll certainly keep them in mind when writing code that doesn’t fall into these categories.

  57. Thøger Kari Jensen says:

    The big question for some applications is actually not whether or not the mutability of the array becomes an issue due to misuse, but whether or not the mutability becomes a *compiler* issue during threading.

    In other words, can the mutability of an array influence multi-threading access speed because the compiler wronfully deems it necessary to perform synchronization?

    This becomes quite important in cases where the threads are rather large but you *know* that they will only perform read operations, and the question is whether or not the compiler and the JIT will be able to recognize this and ditch synchronization.

    I have been unable to find any answers to this so far, but i plan to do some testing in the near future.

  58. Nick Taylor says:

    Mutability of arrays aside, I tend to use my own IReadonlyCollection interface by way of an adapter for the ReadonlyCollection. You can get my code from

  59. I like reviving threads over a year after they were last visited.  Anyhow, are there any active team discussions around having the convenience of an array combined with the beauty of immutability?

  60. George Mauer says:

    Well of course, its just an extension of interface segregation principle.

    Matter of fact, even IEnumerable<T> is often used more than it needs to be. A lot of times you have no desire to give your API's user an ability to enumerate through a collection, you merely want to allow them to call methods on every element – something that should be encapsulated in a Composite pattern

  61. Torbjörn Gyllebring says:

    I'm not saying that I agree particularly much with the BCL teams decision to have "IsReadOnly" on ICollection (and hence IList). But that decisions at least makes returning a readonly IList valid and actually it fit well with the rest of the framework.

    Now I would have liked both "obviously" read-only containers and separated input/output streams, but that's more taste than anything else.

    Great post anyhow.

  62. Bob Foster says:

    > Arrays simply do not model any problem that I have at all well

    Then, of course, don't use arrays. However, arrays (vectors and matrices) do model problems that scientists and engineers have, and nothing else models them as well or efficiently. So to call arrays harmful is to exclude a large and important class of applications simply because you don't happen to work on them. It would be more reasonable to note there is a need for immutable arrays not met by our current languages.

  63. Scott says:

    If you answer and then explain you're a good person.

    If you explain instead of answering you're a weasel, tut.

Comments are closed.

Skip to main content