Is it better to return null or empty collection?
Asked Answered
G

19

488

That's kind of a general question (but I'm using C#), what's the best way (best practice), do you return null or empty collection for a method that has a collection as a return type ?

Goree answered 28/12, 2009 at 15:30 Comment(12)
This is a subjective question, with passionate believers on both sides. There is no commonly accepted "best practice".Twosided
Um, not quite CPerkins. rads.stackoverflow.com/amzn/click/0321545613Counterweight
well, there is a best practice, with reasonable exceptions to it.Rosarosabel
@Twosided - Yes, there is. It is clearly stated in Microsoft's own .NET framework design guidelines. See RichardOD's answer for the details.Nijinsky
while the language in the question is C#, all these guidelines apply to any object-oriented language out there.Rosarosabel
ONLY if the meaning is "I cannot compute the results" should you return null. Null should never have the semantics of "empty", only "missing" or "unknown". More details in my article on the subject: blogs.msdn.com/ericlippert/archive/2009/05/14/…Magnetic
Bozho: "any" is an awful lot of languages. What about Common Lisp, where the empty list is exactly equal to the null value? :-)Tyeshatyg
Duplicate: #1627097Dyanna
Actually, the "duplicate" is about methods which return an object, not a collection. It's a different scenario with different answers.Agile
@EricLippert the link seems to be redirecting to some blog directory page now. Are you able to update the link? Thanks.Groenendael
@TheMuffinMan: You can't edit old comments unfortunately. Microsoft keeps moving where my old blog is. The new link is learn.microsoft.com/en-us/archive/blogs/ericlippert/…Magnetic
I had this question too but I think null is not empty collection and it may cause problem in some codes.Felucca
C
569

Empty collection. Always.

This sucks:

if(myInstance.CollectionProperty != null)
{
  foreach(var item in myInstance.CollectionProperty)
    /* arrgh */
}

It is considered a best practice to NEVER return null when returning a collection or enumerable. ALWAYS return an empty enumerable/collection. It prevents the aforementioned nonsense, and prevents your car getting egged by co-workers and users of your classes.

When talking about properties, always set your property once and forget it

public List<Foo> Foos {public get; private set;}

public Bar() { Foos = new List<Foo>(); }

In .NET 4.6.1, you can condense this quite a lot:

public List<Foo> Foos { get; } = new List<Foo>();

When talking about methods that return enumerables, you can easily return an empty enumerable instead of null...

public IEnumerable<Foo> GetMyFoos()
{
  return InnerGetFoos() ?? Enumerable.Empty<Foo>();
}

Using Enumerable.Empty<T>() can be seen as more efficient than returning, for example, a new empty collection or array.

Counterweight answered 28/12, 2009 at 15:31 Comment(9)
I agree with Will, but i think that "always" is a little excessive. While an empty collection might mean "0 items", returning Null could mean "no collection at all" - eg. if you are parsing HTML, looking for an <ul> with id="foo", <ul id="foo"></ul> could return empty collection; if there is no <ul> with id="foo" a null return would be better (unless you want to handle this case with an exception)Rim
it's not always a question of whether or not "you can easily return an empty array", but rather of whether or not an empty array might be misleading in the current context. An empty array actually means something, as does null. To say that you should always return an empty array rather than null, is almost as misguided as saying you a boolean method should always return true. Both possible values convey a meaning.Whitfield
+ to Bozho. I can see doing this in a ViewModel in WPF, as you can use DataTriggers to switch out UI representations if a property is null. It doesn't mean you have to do this, of course, and a collection property that returns null in any other case would be very bad practice...Counterweight
You should actually prefer returning System.Linq.Enumerable.Empty<Foo>() instead of a new Foo[0]. It is more explicit and saves you one memory allocation (at least, in my installed .NET implementation).Farthingale
Nice one, Trillian. Ironically, looking through Reflector, Empty<T>() returns the static Instance property of EmptyEnumerable<T>, which is just a singleton wrapper around T[0].Counterweight
@Will: OP:"do you return null or empty collection for a method that has a collection as a return type". I think in this case whether it's IEnumerable or ICollection doesn't matter that much. Anyway, if you select something of type ICollection they also return null... I would like them to return an empty collection, but I ran into them returning null, so I thought I'd just mention it here. I would say the default of a collection of enumerable is empty not null. I didn't know it was such a sensitive subject.Leibniz
Related (CodeProject article): Is it Really Better to 'Return an Empty List Instead of null'?Dunnage
I know it's an old anwer, but auto property initializers are a C# 6 enhancement more than a framework feature. You can use them even in a .Net 2.0 project as long as you're using a C#6 compatible compiler. Source, and source. Anyway, +1 because returning null sucks.Guipure
General answers are generally bad. null means one thing, emtpy something different. Don´t mix them by making such generalization.Janiecejanifer
N
166

From the Framework Design Guidelines 2nd Edition (pg. 256):

DO NOT return null values from collection properties or from methods returning collections. Return an empty collection or an empty array instead.

Here's another interesting article on the benefits of not returning nulls (I was trying to find something on Brad Abram's blog, and he linked to the article).

Edit- as Eric Lippert has now commented to the original question, I'd also like to link to his excellent article.

Necessitate answered 28/12, 2009 at 15:44 Comment(5)
+1. It is always best practice to follow the framework design guidelines unless you have a very VERY good reason not to.Counterweight
@Will, absolutely. That's what I follow. I've never found any need to do otherwiseNecessitate
yup, that's what you follow. But in cases that APIs you rely on don't follow it, you are 'trapped' ;)Rosarosabel
@Bozho- yeap. Your answer provides some nice answers of those fringe cases.Necessitate
If you are interested in the article that was originally mentioned in the answer and that is no longer accessible, here it is (archived): Empty Arrays by Wesner Moise.Agential
R
95

Depends on your contract and your concrete case. Generally it's best to return empty collections, but sometimes (rarely):

  • null might mean something more specific;
  • your API (contract) might force you to return null.

Some concrete examples:

  • an UI component (from a library out of your control), might be rendering an empty table if an empty collection is passed, or no table at all, if null is passed.
  • in a Object-to-XML (JSON/whatever), where null would mean the element is missing, while an empty collection would render a redundant (and possibly incorrect) <collection />
  • you are using or implementing an API which explicitly states that null should be returned/passed
Rosarosabel answered 28/12, 2009 at 15:33 Comment(5)
@Bozho- some interesting examples here.Necessitate
I'd kinda see your point eventhough I don't think you should build you code around other fault and by definition 'null' in c# never means something specific. The value null is defined as "no information" and hence to say that it carries specific information is an oximoron. That's why the .NET guidelines state that you should return an empty set if the set is indeed empty. returning null is saying: "I don't know where the expected set went"Parboil
no, it means "there is no set" rather than "the set has no elements"Rosarosabel
I used to believe that, then I had to write lots of TSQL and learned that's not always the case, heheh.Counterweight
The part with Object-To-Xml is spot onDanyel
W
36

There is one other point that hasn't yet been mentioned. Consider the following code:

    public static IEnumerable<string> GetFavoriteEmoSongs()
    {
        yield break;
    }

The C# Language will return an empty enumerator when calling this method. Therefore, to be consistant with the language design (and, thus, programmer expectations) an empty collection should be returned.

Whoremaster answered 28/12, 2009 at 15:57 Comment(2)
I don't technically think that this returns an empty collection.Longspur
@Longspur - No it doesn't. It returns an Enumerable object, whose GetEnumerator() method returns an Enumerator that is (by analagy with a collection) empty. That is, the Enumerator's MoveNext() method always returns false. Calling the example method does not return null, nor does it return an Enumerable object whose GetEnumerator() method returns null.Whoremaster
D
32

Empty is much more consumer friendly.

There is a clear method of making up an empty enumerable:

Enumerable.Empty<Element>()
Deportee answered 30/12, 2009 at 14:28 Comment(1)
Thanks for the neat trick. I was instantiating an empty List<T>() like an idiot but this looks a lot cleaner and is probably a little more efficient too.Disinfect
C
19

It seems to me that you should return the value that is semantically correct in context, whatever that may be. A rule that says "always return an empty collection" seems a little simplistic to me.

Suppose in, say, a system for a hospital, we have a function that is supposed to return a list of all previous hospitalizations for the past 5 years. If the customer has not been in the hospital, it makes good sense to return an empty list. But what if the customer left that part of the admittance form blank? We need a different value to distinguish "empty list" from "no answer" or "don't know". We could throw an exception, but it's not necessarily an error condition, and it doesn't necessarily drive us out of the normal program flow.

I've often been frustrated by systems that cannot distinguish between zero and no answer. I've had a number of times where a system has asked me to enter some number, I enter zero, and I get an error message telling me that I must enter a value in this field. I just did: I entered zero! But it won't accept zero because it can't distinguish it from no answer.


Reply to Saunders:

Yes, I'm assuming that there's a difference between "Person didn't answer the question" and "The answer was zero." That was the point of the last paragraph of my answer. Many programs are unable to distinguish "don't know" from blank or zero, which seems to me a potentially serious flaw. For example, I was shopping for a house a year or so ago. I went to a real estate web site and there were many houses listed with an asking price of $0. Sounded pretty good to me: They're giving these houses away for free! But I'm sure the sad reality was that they just hadn't entered the price. In that case you may say, "Well, OBVIOUSLY zero means they didn't enter the price -- nobody's going to give a house away for free." But the site also listed the average asking and selling prices of houses in various towns. I can't help but wonder if the average didn't include the zeros, thus giving an incorrectly low average for some places. i.e. what is the average of $100,000; $120,000; and "don't know"? Technically the answer is "don't know". What we probably really want to see is $110,000. But what we'll probably get is $73,333, which would be completely wrong. Also, what if we had this problem on a site where users can order on-line? (Unlikely for real estate, but I'm sure you've seen it done for many other products.) Would we really want "price not specified yet" to be interpreted as "free"?

RE having two separate functions, an "is there any?" and an "if so, what is it?" Yes, you certainly could do that, but why would you want to? Now the calling program has to make two calls instead of one. What happens if a programmer fails to call the "any?" and goes straight to the "what is it?" ? Will the program return a mis-leading zero? Throw an exception? Return an undefined value? It creates more code, more work, and more potential errors.

The only benefit I see is that it enables you to comply with an arbitrary rule. Is there any advantage to this rule that makes it worth the trouble of obeying it? If not, why bother?


Reply to Jammycakes:

Consider what the actual code would look like. I know the question said C# but excuse me if I write Java. My C# isn't very sharp and the principle is the same.

With a null return:

HospList list=patient.getHospitalizationList(patientId);
if (list==null)
{
   // ... handle missing list ...
}
else
{
  for (HospEntry entry : list)
   //  ... do whatever ...
}

With a separate function:

if (patient.hasHospitalizationList(patientId))
{
   // ... handle missing list ...
}
else
{
  HospList=patient.getHospitalizationList(patientId))
  for (HospEntry entry : list)
   // ... do whatever ...
}

It's actually a line or two less code with the null return, so it's not more burden on the caller, it's less.

I don't see how it creates a DRY issue. It's not like we have to execute the call twice. If we always wanted to do the same thing when the list does not exist, maybe we could push handling down to the get-list function rather than having the caller do it, and so putting the code in the caller would be a DRY violation. But we almost surely don't want to always do the same thing. In functions where we must have the list to process, a missing list is an error that might well halt processing. But on an edit screen, we surely don't want to halt processing if they haven't entered data yet: we want to let them enter data. So handling "no list" must be done at the caller level one way or another. And whether we do that with a null return or a separate function makes no difference to the bigger principle.

Sure, if the caller doesn't check for null, the program could fail with a null-pointer exception. But if there's a separate "got any" function and the caller doesn't call that function but blindly calls the "get list" function, then what happens? If it throws an exception or otherwise fails, well, that's pretty much the same as what would happen if it returned null and didn't check for it. If it returns an empty list, that's just wrong. You're failing to distinguish between "I have a list with zero elements" and "I don't have a list". It's like returning zero for the price when the user didn't enter any price: it's just wrong.

I don't see how attaching an additional attribute to the collection helps. The caller still has to check it. How is that better than checking for null? Again, the absolute worst thing that could happen is for the programmer to forget to check it, and give incorrect results.

A function that returns null is not a surprise if the programmer is familiar with the concept of null meaning "don't have a value", which I think any competent programmer should have heard of, whether he thinks it's a good idea or not. I think having a separate function is more of a "surprise" problem. If a programmer is unfamiliar with the API, when he runs a test with no data he'll quickly discover that sometimes he gets back a null. But how would he discover the existence of another function unless it occurred to him that there might be such a function and he checks the documentation, and the documentation is complete and comprehensible? I would much rather have one function that always gives me a meaningful response, rather than two functions that I have to know and remember to call both.

Carse answered 28/12, 2009 at 17:16 Comment(15)
Why is it necessary to combine the "no answer" and "zero" responses in the same return value? Instead, have the method return "any previous hospitalizations in the past five years", and have a separate method that asks, "was the previous hospitalizations list ever filled in?". That assumes there's a difference between a list filled in with no previous hospitalizations, and a list not filled in.Prase
@Saunders: See my edit. My reply was too long to fit as a comment, wordy windbag that I am.Carse
But if you return null you are already placing an extra burden on on the caller anyway! The caller has to check every return value for null -- a horrible DRY violation. If you want to indicate "caller did not answer the question" separately, it is simpler to create an extra method call to indicate the fact. Either that, or use a derived collection type with an extra property of DeclinedToAnswer. The rule to never return null is not arbitrary at all, it is the Principle of Least Surprise. Also, your method's return type should mean what its name says it does. Null almost certainly doesn't.Faithfaithful
You're assuming that your getHospitalizationList is only called from one place and/or that all its callers will want to distinguish between the "no answer" and "zero" cases. There will be cases (almost certainly a majority) where your caller does not need to make that distinction, and so you are forcing them to add null checks in places where this should not be necessary. This adds significant risk to your codebase because people can all too easily forget to do so -- and because there are very few legitimate reasons to return null instead of a collection, this will be much more likely.Faithfaithful
Another point. A method called getHospitalizationList which distinguishes between "no answer" and "zero" is doing something outside the scope of what its name says that it does, and violating the Single Responsibility Principle into the bargain. A method that makes that distinction should be called getHospitalizationListOrNullIfNoAnswer.Faithfaithful
RE the name: No function name can completely describe what the function does unless it is as long as the function, and thus wildly impractical. But in any case, if the function returns an empty list when no answer was given, then by the same reasoning, shouldn't it be called "getHospitalizationListOrEmptyListIfNoAnswer"? But really, would you insist that the Java Reader.read function should be renamed readCharacterOrReturnMinusOneOnEndOfStream? That ResultSet.getInt should really be "getIntOrZeroIfValueWasNull"? Etc.Carse
RE every call wants to distinguish: Well, yes, I'm assuming that, or at least that the author of a caller should make a conscious decision that he does not care. If the function returns an empty list for "don't know", and callers blindly treat this "none", it could give seriously inaccurate results. Imagine if the function was "getAllergicReactionToMedicationList". A program that blindly treated "list was not entered" as "patient has no known allergic reactions" could literally result in killing a paitent. You'd get similar, if less dramatic results, in many other systems. ...Carse
... In cases where it truly doesn't matter, or where we only care about data entered in this system so anything unknown is by definition irrelevant, then of course I wouldn't make the distinction.Carse
I would suggest having a method with a parameter indicating how to handle the various corner cases. If the caller is expecting that the list exists, the most useful behavior would be to throw an exception if it doesn't. If the caller's goal is to build a list of all medicines that are known to be prescribed to anyone, a method which returns a list of patient's prescriptions if known, or an empty list if nothing is known about the patient's prescriptions, would be most helpful. And if code is prepared to handle "none" and "unknown" separately, distinct returns would be most helpful.Wellesz
A practice of indicating behaviors using parameters rather than splitting out separate method for each behavior can make it much easier to create wrapper objects, since a single wrapper method will be able to handle all the various behaviors. Even if that method needs some code which distinguishes the different behaviors, using one method will avoid the need to duplicate the code that would be common to all behaviors.Wellesz
The thing about the house example is that it's not a collection. A house price is a single number, which can have a value or be null. So it doesn't apply to the question of whether a collection could legitimately be null. As for the patient example, if a lot of questions could be not answered, perhaps you'd want to have a generic type, e.g. Answerable<T>, akin to Nullable<T> in .NET. It would have a bool Answered property, and a Value of T which would only be populated if Answered == true. This type would clearly call out to a consumer that the value requires special handling.Gaptoothed
@Kyralessa RE house not a collection: Sure. My point was that making no distinction between "price is unknown" and "price = zero" creates ambiguity and wildly inaccurate results. In the same way, making no distinction between "list contents unknown" and "list contains no elements" creates ambiguity and errors.Carse
Well yes, you could create a wrapper type of "Answered<T>", but that's what Nullable<T> was supposed to be for: to make it possible to say that a value is unknown. Why invent your own construct that does exactly the same thing as an existing construct, especially given that the existing construct was explicitly created for exactly this purpose? That's like saying that you think it's inappropriate to use an Integer in some case, so you're going to create your own class, "PositiveAndNegativeNonfractionalNumbers", that works exactly like Integers and use that instead. :-)Carse
@Carse You're getting a bit far afield of the original issue, which is whether it makes any sense to return null rather than an empty collection. The answer to that is: No. The caller should be able to assume that the collection returned is not null. Empty, maybe, but not null. As for Answered<T>, remember that Nullable<T> can't be used for reference types. So you can't use it for a collection.Gaptoothed
Whether it makes sense to return null was the original question. Your assertion that the answer is no begs the question. Why or why not?Carse
W
11

If an empty collection makes sense semantically, that's what I prefer to return. Returning an empty collection for GetMessagesInMyInbox() communicates "you really do not have any messages in your inbox", whereas returning null might be useful to communicate that insufficient data is available to say what the list that might be returned ought to look like.

Whitfield answered 28/12, 2009 at 15:35 Comment(2)
In the example you give, it sounds like the method should probably throw an exception if it can't fulfil the request rather than just returning null. Exceptions are much more useful for diagnosing problems than nulls.Nijinsky
well yes, in the inbox example a null value surely doesn't appear reasonable, i was thinking in more general terms on that one. Exceptions are also great to communicate the fact that something has gone wrong, but if the "insufficient data" referred to is perfectly expected, then throwing an exception there would be poor design. I'm rather thinking of a scenario where it is perfectly possible and no error at all for the method to sometimes not be able to calculate a response.Whitfield
E
7

Returning null could be more efficient, as no new object is created. However, it would also often require a null check (or exception handling.)

Semantically, null and an empty list do not mean the same thing. The differences are subtle and one choice may be better than the other in specific instances.

Regardless of your choice, document it to avoid confusion.

Egis answered 28/12, 2009 at 15:33 Comment(3)
Efficiency should almost never be a factor when considering the correctness of the design of an API. In some very specific cases such as graphics primitives then it may be so, but when dealing with lists and most other high-level things then I very much doubt it.Nijinsky
Agree with Greg, especially given that the code the API user has to write to compensate for this "optimization" may be more inefficient than if a better design were used in the first place.Aideaidedecamp
Agreed, and in most cases it simply isn't worth the optimization. Empty lists are practically free with modern memory management.Fassold
T
7

One could argue that the reasoning behind Null Object Pattern is similar to one in favour of returning the empty collection.

Thrave answered 28/12, 2009 at 16:28 Comment(0)
B
4

Depends on the situation. If it is a special case, then return null. If the function just happens to return an empty collection, then obviously returning that is ok. However, returning an empty collection as a special case because of invalid parameters or other reasons is NOT a good idea, because it is masking a special case condition.

Actually, in this case I usually prefer to throw an exception to make sure it is REALLY not ignored :)

Saying that it makes the code more robust (by returning an empty collection) as they do not have to handle the null condition is bad, as it is simply masking a problem that should be handled by the calling code.

Beckybecloud answered 28/12, 2009 at 15:46 Comment(0)
F
4

I would argue that null isn't the same thing as an empty collection and you should choose which one best represents what you're returning. In most cases null is nothing (except in SQL). An empty collection is something, albeit an empty something.

If you have have to choose one or the other, I would say that you should tend towards an empty collection rather than null. But there are times when an empty collection isn't the same thing as a null value.

Fassold answered 28/12, 2009 at 15:48 Comment(0)
P
4

Think always in favor of your clients (which are using your api):

Returning 'null' very often makes problems with clients not handling null checks correctly, which causes a NullPointerException during runtime. I have seen cases where such a missing null-check forced a priority production issue (a client used foreach(...) on a null value). During testing the problem did not occur, because the data operated on was slightly different.

Punnet answered 28/12, 2009 at 20:39 Comment(0)
S
4

I call it my billion-dollar mistake…At that time, I was designing the first comprehensive type system for references in an object-oriented language. My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn’t resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years. – Tony Hoare, inventor of ALGOL W.

See here for an elaborate shit storm about null in general. I do not agree with the statement that undefined is another null, but it is still worth reading. And it explains, why you should avoid null at all and not just in the case you have asked. The essence is, that null is in any language a special case. You have to think about null as an exception. undefined is different in that way, that code dealing with undefined behavior is in most cases just a bug. C and most other languages have also undefined behavior but most of them have no identifier for that in the language.

Sadowski answered 4/12, 2017 at 16:27 Comment(0)
J
3

From the perspective of managing complexity, a primary software engineering objective, we want to avoid propagating unnecessary cyclomatic complexity to the clients of an API. Returning a null to the client is like returning them the cyclomatic complexity cost of another code branch.

(This corresponds to a unit testing burden. You would need to write a test for the null return case, in addition to the empty collection return case.)

Jenny answered 20/6, 2018 at 18:3 Comment(0)
H
2

We had this discussion among the development team at work a week or so ago, and we almost unanimously went for empty collection. One person wanted to return null for the same reason Mike specified above.

Huygens answered 28/12, 2009 at 15:35 Comment(0)
Q
2

Empty Collection. If you're using C#, the assumption is that maximizing system resources is not essential. While less efficient, returning Empty Collection is much more convenient for the programmers involved (for the reason Will outlined above).

Quiteria answered 28/12, 2009 at 15:39 Comment(0)
A
2

I like to give explain here, with suitable example.

Consider a case here..

int totalValue = MySession.ListCustomerAccounts()
                          .FindAll(ac => ac.AccountHead.AccountHeadID 
                                         == accountHead.AccountHeadID)
                          .Sum(account => account.AccountValue);

Here Consider the functions I am using ..

1. ListCustomerAccounts() // User Defined
2. FindAll()              // Pre-defined Library Function

I can easily use ListCustomerAccount and FindAll instead of.,

int totalValue = 0; 
List<CustomerAccounts> custAccounts = ListCustomerAccounts();
if(custAccounts !=null ){
  List<CustomerAccounts> custAccountsFiltered = 
        custAccounts.FindAll(ac => ac.AccountHead.AccountHeadID 
                                   == accountHead.AccountHeadID );
   if(custAccountsFiltered != null)
      totalValue = custAccountsFiltered.Sum(account => 
                                            account.AccountValue).ToString();
}

NOTE : Since AccountValue is not null, the Sum() function will not return null., Hence I can use it directly.

Anyaanyah answered 20/7, 2013 at 10:1 Comment(0)
D
2

Returning an empty collection is better in most cases.

The reason for that is convenience of implementation of the caller, consistent contract, and easier implementation.

If a method returns null to indicate empty result, the caller must implement a null checking adapter in addition to enumeration. This code is then duplicated in various callers, so why not to put this adapter inside the method so it could be reused.

A valid usage of null for IEnumerable might be an indication of absent result, or an operation failure, but in this case other techniques should be considered, such as throwing an exception.

using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;

namespace StackOverflow.EmptyCollectionUsageTests.Tests
{
    /// <summary>
    /// Demonstrates different approaches for empty collection results.
    /// </summary>
    class Container
    {
        /// <summary>
        /// Elements list.
        /// Not initialized to an empty collection here for the purpose of demonstration of usage along with <see cref="Populate"/> method.
        /// </summary>
        private List<Element> elements;

        /// <summary>
        /// Gets elements if any
        /// </summary>
        /// <returns>Returns elements or empty collection.</returns>
        public IEnumerable<Element> GetElements()
        {
            return elements ?? Enumerable.Empty<Element>();
        }

        /// <summary>
        /// Initializes the container with some results, if any.
        /// </summary>
        public void Populate()
        {
            elements = new List<Element>();
        }

        /// <summary>
        /// Gets elements. Throws <see cref="InvalidOperationException"/> if not populated.
        /// </summary>
        /// <returns>Returns <see cref="IEnumerable{T}"/> of <see cref="Element"/>.</returns>
        public IEnumerable<Element> GetElementsStrict()
        {
            if (elements == null)
            {
                throw new InvalidOperationException("You must call Populate before calling this method.");
            }

            return elements;
        }

        /// <summary>
        /// Gets elements, empty collection or nothing.
        /// </summary>
        /// <returns>Returns <see cref="IEnumerable{T}"/> of <see cref="Element"/>, with zero or more elements, or null in some cases.</returns>
        public IEnumerable<Element> GetElementsInconvenientCareless()
        {
            return elements;
        }

        /// <summary>
        /// Gets elements or nothing.
        /// </summary>
        /// <returns>Returns <see cref="IEnumerable{T}"/> of <see cref="Element"/>, with elements, or null in case of empty collection.</returns>
        /// <remarks>We are lucky that elements is a List, otherwise enumeration would be needed.</remarks>
        public IEnumerable<Element> GetElementsInconvenientCarefull()
        {
            if (elements == null || elements.Count == 0)
            {
                return null;
            }
            return elements;
        }
    }

    class Element
    {
    }

    /// <summary>
    /// https://mcmap.net/q/57260/-is-it-better-to-return-null-or-empty-collection/
    /// </summary>
    class EmptyCollectionTests
    {
        private Container container;

        [SetUp]
        public void SetUp()
        {
            container = new Container();
        }

        /// <summary>
        /// Forgiving contract - caller does not have to implement null check in addition to enumeration.
        /// </summary>
        [Test]
        public void UseGetElements()
        {
            Assert.AreEqual(0, container.GetElements().Count());
        }

        /// <summary>
        /// Forget to <see cref="Container.Populate"/> and use strict method.
        /// </summary>
        [Test]
        [ExpectedException(typeof(InvalidOperationException))]
        public void WrongUseOfStrictContract()
        {
            container.GetElementsStrict().Count();
        }

        /// <summary>
        /// Call <see cref="Container.Populate"/> and use strict method.
        /// </summary>
        [Test]
        public void CorrectUsaOfStrictContract()
        {
            container.Populate();
            Assert.AreEqual(0, container.GetElementsStrict().Count());
        }

        /// <summary>
        /// Inconvenient contract - needs a local variable.
        /// </summary>
        [Test]
        public void CarefulUseOfCarelessMethod()
        {
            var elements = container.GetElementsInconvenientCareless();
            Assert.AreEqual(0, elements == null ? 0 : elements.Count());
        }

        /// <summary>
        /// Inconvenient contract - duplicate call in order to use in context of an single expression.
        /// </summary>
        [Test]
        public void LameCarefulUseOfCarelessMethod()
        {
            Assert.AreEqual(0, container.GetElementsInconvenientCareless() == null ? 0 : container.GetElementsInconvenientCareless().Count());
        }

        [Test]
        public void LuckyCarelessUseOfCarelessMethod()
        {
            // INIT
            var praySomeoneCalledPopulateBefore = (Action)(()=>container.Populate());
            praySomeoneCalledPopulateBefore();

            // ACT //ASSERT
            Assert.AreEqual(0, container.GetElementsInconvenientCareless().Count());
        }

        /// <summary>
        /// Excercise <see cref="ArgumentNullException"/> because of null passed to <see cref="Enumerable.Count{TSource}(System.Collections.Generic.IEnumerable{TSource})"/>
        /// </summary>
        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void UnfortunateCarelessUseOfCarelessMethod()
        {
            Assert.AreEqual(0, container.GetElementsInconvenientCareless().Count());
        }

        /// <summary>
        /// Demonstrates the client code flow relying on returning null for empty collection.
        /// Exception is due to <see cref="Enumerable.First{TSource}(System.Collections.Generic.IEnumerable{TSource})"/> on an empty collection.
        /// </summary>
        [Test]
        [ExpectedException(typeof(InvalidOperationException))]
        public void UnfortunateEducatedUseOfCarelessMethod()
        {
            container.Populate();
            var elements = container.GetElementsInconvenientCareless();
            if (elements == null)
            {
                Assert.Inconclusive();
            }
            Assert.IsNotNull(elements.First());
        }

        /// <summary>
        /// Demonstrates the client code is bloated a bit, to compensate for implementation 'cleverness'.
        /// We can throw away the nullness result, because we don't know if the operation succeeded or not anyway.
        /// We are unfortunate to create a new instance of an empty collection.
        /// We might have already had one inside the implementation,
        /// but it have been discarded then in an effort to return null for empty collection.
        /// </summary>
        [Test]
        public void EducatedUseOfCarefullMethod()
        {
            Assert.AreEqual(0, (container.GetElementsInconvenientCarefull() ?? Enumerable.Empty<Element>()).Count());
        }
    }
}
Deportee answered 17/9, 2014 at 8:54 Comment(0)
E
0

Go seems to be the one language where nil is preferred over an empty array.

https://github.com/golang/go/wiki/CodeReviewComments#declaring-empty-slices

When declaring an empty slice, prefer var t []string over t := []string{}. The former declares a nil slice value, while the latter is non-nil but zero-length. They are functionally equivalent—their len and cap are both zero—but the nil slice is the preferred style.

Erskine answered 24/2, 2022 at 1:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.