AIP-145

Ranges

Services often need to represent ranges of discrete or continuous values. These have wide differences in meaning, and come in many types: integers, floats, and timestamps, just to name a few, and the expected meaning of a range can vary in subtle ways depending on the type of range being discussed.

Guidance

A resource or message representing a range should ordinarily use two separate fields of the same type, with prefixes start_ and end_:

// A representation of a chapter in a book.
message Chapter {
  string title = 1;

  // The page where this chapter begins.
  int32 start_page = 2;

  // The page where the next chapter or section begins.
  int32 end_page = 3;
}

Inclusive or exclusive ranges

Fields representing ranges should use inclusive start values and exclusive end values (half-closed intervals) in most situations; in interval notation: [start_xxx, end_xxx).

Exclusive end values are preferable for the following reasons:

  • It conforms to user expectations, particularly for continuous values such as timestamps, and avoids the need to express imprecise “limit values” (e.g. 2012-04-20T23:59:59).
  • It is consistent with most common programming languages, including C++, Java, Python, and Go.
  • It is easier to reason about abutting ranges: [0, x), [x, y), [y, z), where values are chainable from one range to the next.

Exceptions

In some cases, there is significant colloquial precedent for inclusive start and end values (closed intervals), to the point that using an exclusive end value would be confusing even for people accustomed to them.

For example, when discussing dates (not to be confused with timestamps), most people use inclusive end: a conference with dates “April 21-23” is expected to run for three days: April 21, April 22, and April 23. This is also true for days of the week: a business that is open “Monday through Friday” is open, not closed, on Fridays.

In this situation, the prefixes first and last should be used instead:

// A representation of a chapter in a book.
message Chapter {
  string title = 1;

  // The first page of the chapter.
  int32 first_page = 2;

  // The last page of the chapter.
  int32 last_page = 3;
}

Fields representing ranges with significant colloquial precedent for inclusive start and end values should use inclusive end values with first_ and last_ prefixes for those ranges only. The service should still use exclusive end values for other ranges where this does not apply, and must clearly document each range as inclusive or exclusive.