2

I was looking for an answer to the question of what a DAO should return when a search ends up to be for an entity that does not exist.

There are some generic previous questions related to returning null, but I am looking for an answer specifically in the context of the DAO retrieve scenario.



To be clear, when I say Null Object I am referring to the Null Object pattern. In the Java space, Josh Bloch recommends an empty collection solution in the book Effective Java (See Item 43) which provides an very good introduction to the problem/solution.


Despite being aware of Bloch's advice when I first wrote this question I considered returning null appropriate in a read/retrieval scenario. I'm in good company making a mistake with nulls.

Crowie
  • 202
  • 2
  • 13
  • 2
    What's wrong with your question is that it is very hard to decipher what you are asking. It seems almost a request for a discussion, for which P.SE isn't the right place. – Bart van Ingen Schenau May 14 '13 at 17:25
  • 2
    For some background, [Null References - the Billion Dollar Mistake](http://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare). –  May 14 '13 at 18:00
  • @Brandon: I would use an exception to indicate an error, not a valid empty result (which is what Crowie seems to have in mind). – Giorgio Jan 13 '14 at 09:53
  • @Giorgio I think I agree with you. Sorry if the answer so far indicates otherwise - I should edit to say 'no results' is generally not an error condition. Regardless of it being good or bad some people I have worked with still return null after handling an exception – Crowie Jan 13 '14 at 10:02
  • @Crowie: I agree with you that mapping an exception to null is probably a conceptual error (sweeping an error under the carpet and transforming it to a valid result). On the other hand, what is an error on a lower layer could be a valid result on an upper layer, e.g. if you use some library function whose only way to report a certain condition is to throw an exception. – Giorgio Jan 13 '14 at 10:14

2 Answers2

8

In "Effective Java" item 43 p. 201, Joshua Bloch says, "There is no reason ever to return null from an array- or collection-valued method." He recommends returning a zero-length array or an empty collection (Collections.emptyXxx) when there are legitimately no results. For one thing, it's a pain for the client to double-check everything:

if ( (retVal == null) || (retVal.size() < 1) ) {
    ...
}

Before returning null, ask yourself if the null return value is a result of a programming error on the part of the calling code. Such a check is generally done in the first few lines of a procedure as a defensive check for invalid input values and could legitimately result in throwing an unchecked exception instead of returning null. For my reasoning on this, please see the Checked vs. Unchecked Exceptions entry in my blog.

Scala and Haskell avoid returning null with an Option class. I don't immediately see how this is better than null (other than being type-safe just for the sake of it), but I thought I should mention it as another point of view:

val nameMaybe = request getParameter "name"
nameMaybe match {
  case Some(name) =>
    println(name.trim.toUppercase)
  case None =>
    println("No name value")
}

Bloch suggests that null is an appropriate return instead of an empty collection in C because array lengths are stored separately from arrays and there is no advantage to allocating an empty array. But a null is not the right answer all the time in all languages.

GlenPeterson
  • 14,890
  • 6
  • 47
  • 75
  • 1
    What if there is nothing to return? i.e. calling a method on a service to get the stock ticker price for a stock that does not exist. What would be returned then? – Mike May 14 '13 at 17:36
  • 4
    @Crowie: Page 201 in the 2nd ed., Item #43: "Return empty arrays or collections, not nulls". He speaks about not returning null when you would have otherwise returned an array/collection. – FrustratedWithFormsDesigner May 14 '13 at 17:44
  • @Crowie: I would guess in the case of a DAO read, returning an empty result set would be the closest fit to this advice. – FrustratedWithFormsDesigner May 14 '13 at 17:48
  • 3
    C++ shouldn't differ from Java in this regard, as the answer should be the same for all sufficiently compatible languages: null is only acceptable if the function in question can only return zero or one object. Otherwise, an empty collection clearly indicates that nothing was retrieved. – Bart van Ingen Schenau May 14 '13 at 18:06
  • 1
    @Crowie: Ok, but why not? If the user of your code can determine if nothing was found simply by testing `resultSet.getLength()==0`, why return null instead? Maybe you'd rather throw a `NoDataFound` exception? But I don't think finding nothing when attempting to read from a database is really exceptional (in general). – FrustratedWithFormsDesigner May 14 '13 at 18:09
  • 1
    @Crowie: It's a search for *potentially* many, so I think you should return an empty result set. Yes, you are returning one object (the result set) but the object really just serves as a *container* for *many* objects. If you were returning an *array* of results, then it would probably be less vague. – FrustratedWithFormsDesigner May 14 '13 at 18:10
  • @FrustratedWithFormsDesigner yes that is an answer that I haven't considered. And not considering 'potentially many' is why I wanted to avoid Null object pattern in this situation. Should you assume a result can return many - I suppose you should. Sorry for the edits. Trying not to have a long wasteful chat – Crowie May 14 '13 at 18:13
  • @Crowie: That sounds like a *special* case for your DAO. In which case, you could have a `GetUniqueValueDAO` class which *will* return NULL when no records are found, and since it is implied that no more than 1 record could ever be returned, it might be OK in this case to return NULL. But that's a special case... – FrustratedWithFormsDesigner May 14 '13 at 18:16
  • 9
    The Option (or Maybe) type is not 'being type-safe just for the sake of it'. 1) It forces you to always consider an empty result. 2) It allows you to compose functions, returning null on the first failure. It can make your code considerably shorter and clearer. – lortabac Jan 13 '14 at 09:01
  • 2
    @lortabac +1, fully agree. It is `null` that is arbitrarily unsafe. `null` is not a valid value for any type, and you shouldn't be allowed to assign it to variables any more than you should be allowed to assign a `String` to a non-String variable. A language *could* allow such a thing, and the callers *could* check if the return value was a `String`, but it is arbitrary, error-prone, and subverts the type system. – Doval Feb 13 '14 at 12:47
  • 1
    I think even suggesting that `null` and `Maybe a` are similar is an insult to `Maybe a`. Apart from making "forgetting" about the fail case literally impossible it's alos monadic (which implies a functor which implies an applicative functor etc). With java streams this lets you use `Option.map` operations. In general, it lets you do "railway oriented programming". It's an EXTREMELY powerful and versatile model to work with, as opposed to the crude, typeless and error-prone `null` – sara May 29 '16 at 06:17
5

A search suggests that there will be multiple results which is an easy case - always return a collection. If there are no results, then the collection will simply have no items.

If there can be 0 or 1 result, it depends on the semantics of the search. Can there only be a 1 result because you are artificially limiting the search results to 1? I would go with a collection with 0 or 1 items, the limit could probably change at some point.

If there can truly only be 0 or 1 result, you are probably trying to "search" by an unique identifier or such. In normal application usage, this "search" will never fail. It is not really a search. Your application doesn't generate links with invalid ids or whatever.

However, in exceptional situations such as:

  • A page with links has been loaded and been sitting idle for a while. Some of the resources behind the links have been deleted in the meanwhile. Now when you click such a link, the "search" would fail.
  • The user manually "circumvents" the application and uses the address bar directly to enter arbitrary id numbers.
  • ...

All of the above are exceptions. So it is very easy, throw an exception. Probably a NotFoundException that doesn't need to be caught anywhere that can just bubble to the top for an automatic 404 error page.

Esailija
  • 5,364
  • 1
  • 19
  • 16