June 30th, 2025
like1 reaction

Embracing the power of the empty set in API design: Requesting zero items

A team was proposing a method that was at its essence a Read(n) that takes the maximum number of items to read. The reality was more complicated than that: The parameter n was really a configuration property on an operation, but it had the same meaning: It set the maximum number of items to return.

The team said that their method returns E_INVALID­ARG if you pass n = 0.

I argued that this is an incorrect design: If somebody asks for “at most zero items”, then you should succeed and give them zero items. Zero is at most zero.

For example, maybe the program calculates the size of its window, divides by the height of an item, and requests only as many items as fit in the window without overflowing. After all, there’s no point fetching data that you never use.

And then the user resizes the window so small that no items fit, so the division rounds down to zero, and the program asks for zero items and crashes because “somebody” decided that it was wrong to ask for zero items.

Let them ask for zero items. Give them nothing.

Edge cases are hard, so remove edge cases from the interface.

Related reading: Embracing the power of the empty set in API design (and applying this principle to selectors and filters).

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

8 comments

  • Joe Beans 2 hours ago

    This is exactly why LINQ methods in C# are wrong to penalize callers with a NullReferenceException when passed a null source. Null is the most efficient version of an empty collection, and if you have to check it everywhere, you can’t really write fluent call chains efficiently. Any method that implicitly converts a null input to a non-null empty collection would be a blessing to any business software I’ve ever worked with.

    • GL 1 hour ago

      An empty collection is not the same as no collection.

      Instance-like methods are intended to be called on non-null targets in C#, so any extension method should mimic that behavior unless specifically designed for the other case. Linq methods can be implemented on the instance and not from an extension, so throwing on null is the consistent choice.

  • Simon Geard

    Yes, far too many developers feel a strange compulsion to treat empty collections as a special case... returning null instead of empty if nothing is found, or checking if a collection is empty before iterating over it, that sort of thing. It's pointless, creating extra work for no benefit.

    That said, your example does hint at one case where such sanity checks are meaningful - pagination. If I ask for a page of size 0, the obvious corollary is that I want to know how many such pages of data there are... at which point we're back to division-by-zero, and...

    Read more
  • Dave Gzorple

    I’d argue that return an error on zero is the correct behaviour, it’s notifying the caller that they have a bug in their code. No-one goes to Amazon and orders zero batteries, or asks for zero litres of petrol at the pump, or goes to a takeaway to place an order for zero burgers, so passing in zero to a function like this should alert the caller via an error return, not continue as if nothing unusual was going on.

    • Jacob Manaker 2 hours ago

      “No-one…goes to a takeaway to place an order for zero burgers”

      But people do go to, say, Starbucks and order zero drinks (if you’re meeting somebody there for an interview).

    • Csaba Varga

      Computer programs are not human beings. Analogies of what a person would or wouldn't do don't really work. Would you crash and burn if something unexpected happened in your life?

      You may have missed it, but Raymond has given an example in the post where asking for zero items is not a bug. Whenever your caller arrives at your parameter value via a calculation, they may happen to arrive at one of the edge cases.

      To put it in different terms: you either handle a request for zero items yourself, or you force all your callers to do their own zero checks...

      Read more
  • Nick · Edited

    Completely agree about eliminating edge cases and aggravating exceptions/errors like that, but following convention is more important. For example, in many APIs a limiting value of 0 means "unlimited" so if that's the case here then this method should behave the same.

    Of course, sometimes -1 means unlimited. Or any negative number. Or you're supposed to use . Or . Etc, etc. One of my favorites is the conflict in .NET between and .

    I like having an explicit way to signal that a response should be unlimited, but admit that just using a Very...

    Read more
  • IS4 19 hours ago

    A slight issue with this are other method contracts. For example when reading from a byte stream, the method could promise to return 0 if and only if the stream is at the end, so either it reads at least one element or indicates the end by returning 0. That is incompatible with reading 0 bytes, so you end up with an edge case either way.