Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I often find myself in need to create empty collections. One of those days several years ago, I wrote something like the following to address that:

public static class Array<T>
{
    // As a static field, it gets created only once for every type.
    public static readonly T[] Empty = new T[0];
}

I didn't know about Enumerable<T>.Empty(); maybe it didn't exist back then. Although I know now, I still use this one. Maybe because I know the actual implemention or maybe I just overly used to it.

// All these variables share the same array's reference.
string[]            empty1 = Array<string>.Empty;
IEnumerable         empty2 = Array<string>.Empty;
IEnumerable<string> empty3 = Array<string>.Empty;

Although switching to Enumerable<T>.Empty() is probably the best since it's now the de facto way to create an empty collection but I still have my doubts.

I wrote this firstly because it does caching of its empty array references but MSDN says Enumerable<T>.Empty() does cache the empty results, too.

So the only advantage of using Array<T> I can think of now, is that it returns an array:
There are still many functions that need an array of values instead of IEnumerable<T>, IList<T> or IReadOnlyList<T>. And array implements all of these so it can be used anywhere.


What do you think about this class?
Can you see any other advantages/disadvantages of it over Enumerable<T>.Empty()?

And about implementation:
Do you think making the caching using a static field would cause any problem?

share|improve this question
    
I wasn't aware of this little gem. Thanks! –  Jesse C. Slicer Jan 11 '13 at 14:27
    
@Jesse: You sir, are very welcome. –  Şafak Gür Jan 11 '13 at 14:46
    
What are your typical use cases for this class? –  Leonid Jan 13 '13 at 15:16
    
@Leonid: I use it mostly on socket programming (to send an empty frame) and on collection returning methods that are called often: IEnumerable<Foo> GetRelatedFoos(Foo foo) { if (foo.Operations == 0) return Array<Foo>.Empty; return GetRelatedFoosInternal(foo); } where GetRelatedFoosInternal(Foo foo) is an iterator block. By separating these methods I can avoid initializing the iterator's state machine unless necessary and by returning Array<Foo>.Empty instead of new Foo[0] I can use the single, empty Foo[] instance for every GetRelatedFoos call that should return empty. –  Şafak Gür Jan 15 '13 at 10:25

3 Answers 3

up vote 2 down vote accepted

Your solution is absolutely correct and practical.

In fact Enumerable.Empty<T> also returns empty array under the hood, just slightly in a different way (they have a separate instance holder class that is lazily initialized).

share|improve this answer
    
Thank you and +1 for the insight about Enumerable<T>.Empty's current implementation. Returning arrays and accepting array parameters are considered as bad practices these days so I get why it's return type is IEnumerable<T> (even if it returns an array) but I guess I'll keep using my own implementation since I can also use it as IEnumerable<T>, IList<T> and IReadOnlyList<T>. Thanks again for clarifying. –  Şafak Gür Jan 12 '13 at 13:18

I think it entirely depends on context.

Enumerable<T>.Empty() was clearly introduced for syntactic sugar in Linq. I see no reason to use it over a plain old new-statement.

The wider question about caching and efficiency depends on the code-base. Calling a list "Empty" explicitly states intent and could help readability, but if you later go on to add items to that collection in any way, it actually makes the code more confusing.

As far as any problems with the "cached, static" field go, the obvious problem is that if someone was foolish enough to place a lock on that static list, it could cause all manner of issues in your application as it'd act as a point of coupling.

I'd always avoid using shared static references if you don't need them for any specific reason, especially if it's a perceived performance problem that has never been encountered. You can't really get much safer than an instance variable with a new empty list in it.

Conversely, if you're really up against the wire with performance, there may be a good reason here, but you'd probably find that if you're micro-optimising list initialisation, there's a better higher level optimisation to be made.

share|improve this answer
1  
Well, one of the reasons I went with array is that arrays with no elements are completely immutable. Since the field is also read-only, there is no way someone can change that cached instance of the array (it will forever be empty). About making it static: There are a lot of public static fields (and singletons that return static instances) even in BCL, so the probability of someone may put o lock on them shouldn't affect an API's design in my opinion. Also, I believe if someone does that, he really deserves the problems it will cause. –  Şafak Gür Jan 11 '13 at 14:14
    
+1 for your point on my approach being a micro-optimization though; you're right about that. I could just return new T[0] and that wouldn't hurt the performance in most of the cases but I couldn't see a reason for it. Now I know that Enumerable<T>.Empty() also does caching and I think locking Enumerable<string>.Empty() does probably the same thing with locking Array<string>.Empty. –  Şafak Gür Jan 11 '13 at 14:15

this kind of implementation of static default type for a given type is a well known pattern called "Nullobject Pattern" (more info here : http://en.wikipedia.org/wiki/Null_Object_pattern).

I've used this to avoid comparing to null and instead return objects of the given type that have default values.

example:

public class Person
{
  public string Name {get;set;}
  public uint Age {get;set;}


  //chaining constructor pattern
  public Person : this(string.empty,default(uint))
  {
  }
  public Person(string name,uint age)
  {
     Name=name;
     Age=age;
  }

  //null object pattern
  private static readonly Person _defaultPerson = new Person();

  public static Person Null 
  {
    return _defaultPerson;
  }
}
share|improve this answer
1  
I would avoid uint. Yes, the age is not supposed to be negative, neither is index or the size of the collection, and yet uint is not widely used in libraries because of reasons. –  Leonid Jan 13 '13 at 15:15

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.