14

I was recently asking someone why he preferred to return a strongly-typed array over an IList. I had always thought that programming against an interface was the most flexible and best way program when faced with a project having a long life. So it struck me as odd when he replied:

We typically prefer immutable types over mutable ones. Arrays are immutable. IList is not.

I'm not entirely sure I understand this statement. Can anyone help clarify this?

Thanks for any help you guys can provide.

Rik
  • 28,507
  • 14
  • 48
  • 67
mkelley33
  • 5,323
  • 10
  • 47
  • 71

11 Answers11

13

Whoever "he" is, is in 100% wrong on the topic. Arrays are a very much mutable. This is in fact one of the reasons not to return an array. There is no way to prevent a caller from changing the elements of an array to whatever they please.

The only way in which an Arrray is immutable is in it's length. Once an array is allocated, it's length cannot be changed. Even APIs such as Array.Resize don't actually resize the array, they just allocate a new one, copy the contents and return the new array (by reference in this case).

I do agree however that there are many cases in which it is better to return immutable data. The primary one is that it allows you to return a reference to an internal collection of a class without doing a complete copy and at the same time preventing the caller from messing with your internal state. Most mutable collections cannot make such guarantees.

JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 2
    "in which it is valid.." - do you mean "in which it is better"? – peterchen May 02 '09 at 23:49
  • Well, I wouldn't go that far..."He's" a really amazing coder, but I think he may be referring to some aspect in one of the comments below; however, I fail to see what this "buys" me or my program. If I'm using a repository pattern to return a list of objects, why must it be an array instead of IList? – mkelley33 May 03 '09 at 00:04
  • @mkelley33, which part are you talking about? He is certainly wrong about Arrays being immutable regardless of skill. They simple are mutable structures. This does not though make him less of a coder. Everyone is prone to mistakes (I myself try to make 2 or 3 a day) and this is one I've seen many people make. I would certainly argue for return an IList over an array or better yet an actual immutable structure. It just gives you more flexibility over time. – JaredPar May 03 '09 at 00:45
  • Oh I don't think he's flawless by any means, but I think I may have quoted him out of context, though I'm still trying to understand the context. So I have an IRepository that has GetAll method returning IList. How does immutability give you more flexibility over time? Thanks for all the help. – mkelley33 May 03 '09 at 15:01
  • @mkelley, I meant more that returning an interface to a mutable or immutable collection gave you more flexibility over time. – JaredPar May 03 '09 at 15:25
11

I think he maybe thought since an array's length property is immutable, then somehow arrays are more immutable than IList or maybe he used the wrong word and interchanged concrete with immutable. Who knows but it's an odd answer.

I think with returning a List there is something slightly implied that it's ok to modify it or that it may change while returning an array doesn't imply that as much.

For example, If you had an object model on top of a repository and had a method like GetCars() that returned a List and a junior programmer saw cars.Add(Car c) ... Would you think he was completely insane for thinking cars.Add(new Car()) might actually add a car into the repository? Arrays are just inherently more explicit.

I think List usage is more appropriate in properties, like Page.Controls.Add

I prefer returning arrays more often than List for several reasons.

  • Habit. Collections in 1.0/1.1 SUCKED

  • I prefer that my methods return the simplest & most lightweight object they can. If I need to make an Array a List it is trivial.

  • They can be used in .net 1.1 and it reduces the surface are of refactoring if I ever needed to support older versions of the runtime I can reuse at least some of my code or apply an identical object model.

Chad Grant
  • 44,326
  • 9
  • 65
  • 80
  • This gave me the "ah-ha" moment I was looking for! Returning T[] from a repository is less "leaky" (as in Law of Leaky Abstractions). If I wanted to add something to the repository, I would call it's Add/Insert method right? So it would be counterproductive/counter-intuitive for me to assume that adding something to the list returned would be able to participate in a Unit of Work or work as anticipated. When using an IRepository, he is 100% right! Albeit the explanation he gave me was more along the lines of what you said: Array is more immutable than IList in some regards. Thank you so much! – mkelley33 May 03 '09 at 15:19
  • 2
    +1 for a junior seeing List.Add might think it's a good idea (vs. not seeing it w/ Array) – Jake Berger Nov 16 '11 at 18:09
10

I always prefer a ReadOnlyCollection. All the advantages of a List, but Read Only.

Michael Stum
  • 177,530
  • 117
  • 400
  • 535
7

One point he could have meant is that IList includes the Insert, Remove, and Add methods, so the collection itself can be modified. T[], on the other hand, cannot have elements added to it.

I should add that FxCop recommends returning ReadOnlyCollection instead. The indexer is read-only, so you can't change the elements, and the Add and other such methods all throw NotSupportedException.

John Saunders
  • 160,644
  • 26
  • 247
  • 397
  • 1
    Cool! That's great. I use FxCop from time to time at my job, and I've always wondered about some of those recommendations. Thanks for the clarification! – mkelley33 May 03 '09 at 00:34
7

In principle he's right, but he doesn't know how to practice it properly...

We typically prefer immutable types over mutable ones.

That is correct. Immutable types are nicer to work with

Arrays are immutable. IList is not.

That is not correct. Neither of those are immutable.

If you want to return a collection that is immutable, return an IEnumerable<T> or a ReadOnlyCollection<T> (using the List<T>.AsReadOnly method). Still those doesn't protect the objects if they themselves are not immutable. Eventhough you can only read from the collections, you can still change the data in each object if they allow it.

Also, you should consider the "ownership" of the collection that you are returning. If you are creating an array for the sole purpose of returning it, then there is no reason not to give full control to it. If you on the other hand are returning a collection that is a member of the class, you should only allow as little access to it as is needed.

Guffa
  • 687,336
  • 108
  • 737
  • 1,005
2

I don't understand it either. Arrays are very much mutable, except for their size. Individual elements can still be modified. Maybe he meant arrays are value types and Lists are reference types. I don't know.

Anyway, you should probably have a look at Eric Lippert's opinion on the subject. Could provide you with some ammo for discussion, too.

Rik
  • 28,507
  • 14
  • 48
  • 67
  • Thank you. I've read that article, thus the confusion lol. Given the varying opinions on the subject of mutability (what is and is not) I'd have to go with my gut instinct and return IList until proven otherwise. Let me just say that I am totally indebted to the person that supplied the quote in this question's description. "He-who-must-not-be-name-out-of-respect" is an amazing coder and inspiration, but I don't blindly follow so I'll have to wait until I hear his rebuttle to the arguments provided here! Thanks again. – mkelley33 May 02 '09 at 23:55
  • Thinking for yourself, good! :) Good luck convincing your friend. – Rik May 03 '09 at 00:01
1

Perhaps this someone does not know what he is talking about?

Brian
  • 117,631
  • 17
  • 236
  • 300
1

The reason to use an Interface as return type over the actual type itself, is to hide the internal implementation from the caller. This allowes the implementation to change the actual type without repurcusions to the rest of the application.

It does not make any sense to copy an internally used collection into an array for external use, for no other reason than mutable or immutable.

Seperate issues are: - return a list of strongly typed data or not. IList or IList. The use of strongly typed data is always preferred. - mutable or immutable. ICollection,IList or IEnumerator Return with what you want to allow to the data. For a readonly list return only a IEnumerator. If the caller is allowed to modify the collection use ICollection or IList.

0

Basically he's saying "we prefer structures which can't be changed easily at run time, because we believe them to be less vulnerable to errors." Whether that's correct in this case is another question.

Charlie Martin
  • 110,348
  • 25
  • 193
  • 263
  • Hmmm. I like that, but don't know if its more valuable than programming against an IList, since I have more flexibility over the implementation. Thanks for the help. That makes his position a little clearer. – mkelley33 May 03 '09 at 00:07
0

Perhaps he meant the size of the array as "immutable"? Basically, you declare the size once and you're stuck with it. With lists, you can always use "Add".

I suppose that if you're sure about the size of the list, perhaps array is a bit faster?

luiscubal
  • 24,773
  • 9
  • 57
  • 83
  • That's exactly what I assumed, but I don't really know what that buys me when working with the repository pattern. Thanks! – mkelley33 May 02 '09 at 23:59
0

Well. IList is mutable in the sense that you can add and remove items, rather than just change the items that are already there. An array lets you mess with individual items, but a particular index will never become entirely invalid. There's any number of reasons to prefer immutability -- it makes the surface area for accidental data corruption much smaller, for example.

Promit
  • 3,497
  • 1
  • 20
  • 29
  • Use ICollection, and return one which is read-only if you return one. Arrays implement this interface, so that one can choose to pass interfaces or lists into such methods. Count, Add and Remove is defined on the generic ICollection interface. – Lucero May 03 '09 at 00:00