I was asked on Twitter why Python uses 0-based indexing, with a link to a new (fascinating) post on the subject (http://exple.tive.org/blarg/2013/10/22/citation-needed/). I recall thinking about it a lot; ABC, one of Python's predecessors, used 1-based indexing, while C, the other big influence, used 0-based. My first few programming languages (Algol, Fortran, Pascal) used 1-based or variable-based. I think that one of the issues that helped me decide was slice notation.

Let's first look at use cases. Probably the most common use cases for slicing are "get the first n items" and "get the next n items starting at i" (the first is a special case of that for i == the first index). It would be nice if both of these could be expressed as without awkward +1 or -1 compensations.

Using 0-based indexing, half-open intervals, and suitable defaults (as Python ended up having), they are beautiful: a[:n] and a[i:i+n]; the former is long for a[0:n].

Using 1-based indexing, if you want a[:n] to mean the first n elements, you either have to use closed intervals or you can use a slice notation that uses start and length as the slice parameters. Using half-open intervals just isn't very elegant when combined with 1-based indexing. Using closed intervals, you'd have to write a[i:i+n-1] for the n items starting at i. So perhaps using the slice length would be more elegant with 1-based indexing? Then you could write a[i:n]. And this is in fact what ABC did -- it used a different notation so you could write a@i|n.(See http://homepages.cwi.nl/~steven/abc/qr.html#EXPRESSIONS.)

But how does the index:length convention work out for other use cases? TBH this is where my memory gets fuzzy, but I think I was swayed by the elegance of half-open intervals. Especially the invariant that when two slices are adjacent, the first slice's end index is the second slice's start index is just too beautiful to ignore. For example, suppose you split a string into three parts at indices i and j -- the parts would be a[:i], a[i:j], and a[j:].

So that's why Python uses 0-based indexing.

Let's first look at use cases. Probably the most common use cases for slicing are "get the first n items" and "get the next n items starting at i" (the first is a special case of that for i == the first index). It would be nice if both of these could be expressed as without awkward +1 or -1 compensations.

Using 0-based indexing, half-open intervals, and suitable defaults (as Python ended up having), they are beautiful: a[:n] and a[i:i+n]; the former is long for a[0:n].

Using 1-based indexing, if you want a[:n] to mean the first n elements, you either have to use closed intervals or you can use a slice notation that uses start and length as the slice parameters. Using half-open intervals just isn't very elegant when combined with 1-based indexing. Using closed intervals, you'd have to write a[i:i+n-1] for the n items starting at i. So perhaps using the slice length would be more elegant with 1-based indexing? Then you could write a[i:n]. And this is in fact what ABC did -- it used a different notation so you could write a@i|n.(See http://homepages.cwi.nl/~steven/abc/qr.html#EXPRESSIONS.)

But how does the index:length convention work out for other use cases? TBH this is where my memory gets fuzzy, but I think I was swayed by the elegance of half-open intervals. Especially the invariant that when two slices are adjacent, the first slice's end index is the second slice's start index is just too beautiful to ignore. For example, suppose you split a string into three parts at indices i and j -- the parts would be a[:i], a[i:j], and a[j:].

So that's why Python uses 0-based indexing.

View 13 previous comments

- Ian Danforth+30This is one of the few things I truly hate about python. (Most of the time I'm a Python zealot) Hearing it called 'beautiful' boils my blood. It's such an anti-human way of thinking about a list of items.

Consider, there is a line up of 10 people, and you want to divide them into three groups. No one in their right mind would say I want group one to start with peter and end with jane, and group two to start with jane, and end with tom, and group three to start with tom and end with frank.

A natural, human centered mindset makes you think of about inclusive groupings that start from 1 and go to the total count of the group.

The kind of numbers-first, people-second view of elegance and beauty is fundamental to why programming is considered 'hard.' In so many other ways python gets this right, 0-indexing and half-open slicing are giant ugly warts.Oct 23, 2013 - Ralph H.+2+Kevin Houlihan this and that mistakes were made since most people do not start counting with 0.Oct 23, 2013
- +Ian Danforth Have you never split people up by indicating just who the new group starts with? Using your example, saying something like "lets have Peter start the first group, Jane start the second group, and Tom start the third group." Professors without a good memory of students names do it all the time!Oct 23, 2013
- +Ian Danforth Computer programming, and computer sciences in general, have very little to do with "natural , human centered mindset" and everything to do with math. Closed-ranges and open-ranges (and half-open ranges) map naturally to 0-based indexing, whereas 1-based indexing requires massaging your numbers to prevent off-by-one errors.Oct 23, 2013
- The 1st number is '0', and '1' is the 2nd. It's a fact.Oct 23, 2013
- Jeff Hammond+21Fortran gets it right, not with 1-based indexing, but with user-defined indexing. You can index a 7-element array from -3 to 3 if you want.Oct 23, 2013

Commenting is disabled for this post.