4 ms·
> we should have simply started counting centuries from zero Latin, like Lua, is 1-indexed.
by drewcoo 2y ago
> we should have simply started counting centuries from zero
Latin, like Lua, is 1-indexed.
- usrusr 2y agoAnd look at the bloodshed that caused! https://douglasadams.com/dna/pedants.html https://douglasadams.com/dna/pedants.html
- IshKebab 2y agoI feel like the Romans had an excuse for that mistake. Not sure about Lua.
- bigstrat2003 2y agoI don't think it is a mistake for Lua. The convention to zero-index arrays is not sacrosanct, it's just the way older languages did it (due to implementation details) and thus how people continue to do it. But it's very counter-intuitive, and I think it's fair game for new languages to challenge assumptions that we hold because we're used to past languages.
- antonvs 2y agoIt's not counter-intuitive at all, it only seems that way because people are now used to languages with zero-based indexing. That's almost entirely because of the C language, which used pointer offset arithmetic with its arrays. Outside of that machine context, where an array is a contiguous block of RAM that can be indexed with memory pointers, there's no particular reason to do offset indexing. 1-based works just fine - "first element, second element" - works just fine and is perfectly intuitive. Different types of indexing can make sense in different situations. Some languages even allow that. In Ada, for example, arrays can start at whatever index you define.
- IshKebab 2y ago> 1-based works just fine It really doesn't. You can make it work obviously but you end up with much less elegant code, with +1 and -1 all over the place. E.g. for accessing a row of a matrix you get [width(i-1)+1, widthi+1) instead of the far saner [widthi, (width+1)i) Generic code also becomes much more awkward.
- antonvs 2y agoBoth are less elegant in different scenarios. In many business scenarios with zero-based indexes, you need i+1 everywhere because no-one talks about the e.g. the zeroth year of a company's operation. Neither is a true one-size-fits-all solution. They're different kinds of indexes that serve different purposes. The choice of zero-based everywhere is an engineering tradeoff, nothing more.
- IshKebab 2y ago> In many business scenarios with zero-based indexes, you need i+1 everywhere because no-one talks about the e.g. the zeroth year of a company's operation. Perhaps, but this is extremely rare compared to tasks that are far more elegant with 0-based indexing. Also the worst you can get there is a single +1 in the display code, while trying to shoe-horn algorithms into 1-based code can get much more awkward.
- demurgos 2y agoThere are reasons unrelated to pointer implementations such as the interval argument from Dijkstra's article or conversions between flat and multidimensional array indexes. There's a reason why most mathematical sequences start at zero: it leads to simpler expressions. Vec (and especially matrix) indexing should have been zero-based.
- weinzierl 2y ago> "it's just the way older languages did" It's a C family (predecessors and descendants) idiosyncrasy that very unfortunately got out of hand. Most other old languages had either 1-based indexing or were agnostic. Most notably FORTRAN, which is the language for numerical calculations is 1-based. The seminal book Numerical Recipies was first published as 1- based for FORTRAN and Pascal and they only latter added a 0-based version for C. Personally, coming from Pascal, I think the agnostic way is best. It is not only about 0-based or 1-based but that the type system encodes and verifies the valid range of index values, e.g. in Pascal you define an array like this: temperature = array [ -35 .. 60 ] of real; You will get an immediate compule-time error if you use temperature[61]; At least with Turbo Pascal you could chose if you wanted run-time checks as well. I have a hard time wrapping my head around the fact that this feature is pretty much absent from any practically used language except ADA.
- IshKebab 2y agoIt's not sacrosanct but by the time Lua was created it was very clearly the right choice.
- afiori 2y agoIt is the best choice, but the difference is mostly in working manually with slices and offsets and array windows, for indexing and iterating they are mostly the same with maybe a small benefit for mathy notation (the reason why Julia is 1 indexed)
- worstspotgain 2y agoZero-based arrays are counter-intuitive for a while, but if you deal with a lot of data, you typically realize that it's a small price to pay to make manipulation much easier in many contexts. For instance, if you have a ring buffer of size N and an unwrapped position P, the wrapped position is: Zero-based: P % N One-based: ((P - 1) % N) + 1 It might seem trivial, but each +/-1 is an opportunity for confusion and a bug nest. With zero-based arrays, it's often the case that the only required +/-1's are when producing and consuming human-readable one-based text. The next stop on the zero-based epiphany train is the realization that a convenient way to store a range is a { first, first_past } tuple. The size of the range is (first_past - first). The whole-array range is { 0, size }, while a simple empty range is { 0, 0 } (zero is often the default initialization, simplifying things further.) Both elements are indices, so they can be similarly manipulated, compared and range-checked, making many 'if' clauses easier to think about and verify. If there is a bug, it often ends up being harmless because of the arithmetic properties of this scheme. Once you start dealing with multiple ranges, the advantages are even more obvious. Two ranges are adjacent iff (first_a == past_b || first_b == past_a). The intersection of two ranges is { max(first_a, first_b), min(past_a, past_b) }, which is nonempty iff they overlap. An array of M adjacent ranges is stored as a uniform (M+1)-tuple. This realization has become so second-nature for me that I'm probably overlooking four or five even better examples here.