Why do Lua arrays(tables) start at 1 instead of 0?

ArraysLuaLua Table

Arrays Problem Overview


I don't understand the rationale behind the decision of this part of Lua. Why does indexing start at 1? I have read (as many others did) this great paper. It seems to me a strange corner of a language that is very pleasant to learn and program. Don't get me wrong, Lua is just great but there has to be an explanation somewhere. Most of what I found (on the web) is just saying the index starts at 1. Full stop.

It would be very interesting to read what its designers said about the subject.

Note that I am "very" beginner in Lua, I hope I am not missing something obvious about tables.

Arrays Solutions


Solution 1 - Arrays

Lua is descended from Sol, a language designed for petroleum engineers with no formal training in computer programming. People not trained in computing think it is damned weird to start counting at zero. By adopting 1-based array and string indexing, the Lua designers avoided confounding the expectations of their first clients and sponsors.

Although I too found them weird at the beginning, I have learned to love 0-based arrays. But I get by OK with Lua's 1-based arrays, especially by using Lua's generic for loop and the ipairs operator—I can usually avoid worrying about just how arrays are indexed.

Solution 2 - Arrays

In Programming in Lua's first discussion of tables, they mention:

> Since you can index a table with any value, you can start the indices of an array with any number that pleases you. However, it is customary in Lua to start arrays with 1 (and not with 0, as in C) and several facilities stick to this convention.

Later on, in the chapter on data structures, they say almost the same thing again: that Lua's built-in facilities assume 1-based indexing.

Anyway, there are a couple conveniences to using 1-based indexing. Namely, the # (length) operator: t[#t] access the last (numeric) index of the table, and t[#t+1] accesses 1 past the last index. To someone who hasn't already been exposed to 0-based indexing, #t+1 would be more intuitive to move past the end of a list. There's also Lua's for i = 1,#t construct, which I believe falls under the same category as the previous point that "1 to the length" can be more sensible than indexing "0 to the length minus 1".

But, if you can't break the mindset of 0-based indexing, then Lua's 1-based indexing can certainly be more of a hindrance. Ultimately, the authors wanted something that worked for them; and I'll admit I don't know what their original goal was, but it's probably changed since then.

Solution 3 - Arrays

My understanding is that it's that way just because the authors thought it would be a good way to do it, and after they rolled the language out to the public that decision calcified considerably. (I suspect there would be hell to pay were they to change it today!) I've never seen a particular justification beyond that.

Solution 4 - Arrays

Perhaps a less significant point, but one I haven't heard mentioned yet: there is better symmetry in the fact that the first and last characters in a string are at 1 and -1 respectively, instead of 0 and -1.

Solution 5 - Arrays

Lua libraries prefer to use indices which start at 1. However, you can use any index you want. You can use 0, you can use 1, you can use -5. It is even in their manual, which can be found at (https://www.lua.org/pil/11.1.html).

In fact, something cool here is internal lua libraries will treat SOME passed 0's as 1's. Just be cautious when using ipairs.
So that: ("abc"):sub(0,1) == "a" and ("abc"):sub(1,1) == "a" will be true.

 You can start an array at index 0, 1, or any other value:

-- creates an array with indices from -5 to 5
a = {}
for i=-5, 5 do
  a[i] = 0
end

Solution 6 - Arrays

The specific definitions of array index in C and Lua, are different.

In C array, it means: item address offset of the array address.

In Lua array, it means: the n-th item in array.

Why most languages use 0-based index? Because the compiler code with offset definition is more convenient and effective. They mostly handle addresses.

And the Lua. This is the code of lua 5.3.5 for table index with C:

const TValue *luaH_getint (Table *t, lua_Integer key) {
  if (l_castS2U(key) - 1 < t->sizearray)
    return &t->array[key - 1];
  else {
    Node *n = hashint(t, key);
    for (;;) {
      if (ttisinteger(gkey(n)) && ivalue(gkey(n)) == key)
        return gval(n);
      else {
        int nx = gnext(n);
        if (nx == 0) break;
        n += nx;
      }
    }
    return luaO_nilobject;
  }
}

We should focus on the code &t->array[key - 1], it have a subtraction operation. It is not effective compared with 0-based index.

But, the 1-based index is more neared with human being languages. We focus more on n-th item in English, Chinese, Japanese and also.

So, I guess the Lua designers choose 1-based index, they choose easy understanding for pure newer of program, give up the convenience and effectiveness.

Solution 7 - Arrays

The real reason is that the language is an implementation of the definition in a law of Portugal and the major development centre was in Brazil and their preference is to avoid the use of zero or empty or nothing as an index or subscript. However the language does permit the use of a start index other than 1 in a table creating function in some versions.

Solution 8 - Arrays

In your example, table[0] will always return nil(null), unless you assign value to it yourself, like table[0] = 'some value' and then table[0] will return 'some value', which you assigned.

Here's an example:

tbl = {"some"}
print("tbl[0]=" .. tostring(tbl[0]))
print("tbl[1]=" .. tostring(tbl[1]))
nothing = {}
print("nothing[0]=" .. tostring(nothing[0]))
print("nothing[1]=" .. tostring(nothing[1]))
nothing[0] = "hey"
print("(after assign)\nnothing[0]=" .. tostring(nothing[0]))

Solution 9 - Arrays

It makes sense to everyone, that if

table = {}

table is empty. So, when

table == {something}

The table contains something so what it contains is index 1 in table, if you know what I mean.

What I meant is that table[0] exists, and its table = {}, which is empty, now a programmer won't call a empty table, it sets them, and then fills it, it will be useless to find an empty table every time you want to call it, so it's simpler to just create an empty table.

My English won't get better and that's my best grammar. If you don't like it, you're free to not keep reading it, but giving -rep for someone trying to help makes people not want to help at all, especially for something like grammar. I'm a man of numbers and vars, not grammar. Sorry.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKhaled AlshayaView Question on Stackoverflow
Solution 1 - ArraysNorman RamseyView Answer on Stackoverflow
Solution 2 - ArraysMark RushakoffView Answer on Stackoverflow
Solution 3 - Arraysdash-tom-bangView Answer on Stackoverflow
Solution 4 - ArraysVXZView Answer on Stackoverflow
Solution 5 - Arraysuser2262111View Answer on Stackoverflow
Solution 6 - ArraysRenshawView Answer on Stackoverflow
Solution 7 - ArraysDeveloperView Answer on Stackoverflow
Solution 8 - ArraysBladeMightView Answer on Stackoverflow
Solution 9 - ArraysWeskerView Answer on Stackoverflow