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

9

177

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.

Tuscarora answered 7/5, 2010 at 1:52 Comment(25)
The default scope is also global. The two biggest misfeatures of Lua.Tumefaction
I would not call starting at 1 a misfeature. It actually makes more sense - programmers are just so well trained to think in terms of 0-based indexing from other languages that we don't like it. We are also trained to think 5/2 = 2. That doesn't make it right.Arable
It's interesting how many scripting languages have had default global scope, which I too think is the wrong default. But Icon has the same problem, and awk doesn't even provide a way to declare local variables except as surplus parameters. Scheme also has default global scope. @theatrus can you point to a scripting language with default local scope so we can see what are the consequences?Unconditional
@BlueRaja-DannyPflughoeft: no. Zero indexing makes more sense - humans are just so well trained in starting counting with 1 that languages that start with 0 are initially confusing. But I'd love to refer you to Edsger Dijkstra here: cs.utexas.edu/users/EWD/ewd08xx/EWD831.PDFMyramyrah
@nightcracker: When you count apples on a table, you count the first one as "one," the second one as "two," etc. Nobody counts the first one as "zero" and then adds one at the end; counting from zero is simply, unarguably, counter-intuitive. Yes, I realize that's how the indexing works internally, but that's why we call it an abstraction.Arable
I never understood all the love towards 0-based indexing. It's nice for offsets (how many items to skip from the start?) and subsequences (0 ≤ x < n), but looks wrong for basic things (the second element is called one? The tenth element corresponds to index nine? WAT?). Even programmers count from 1 when they try to find a line reported by the compiler...Lynxeyed
@NormanRamsey PHP has a default local scope. Make of it what you want :)Chickenlivered
I think the main downside of 0-based indexing is that it is not consists with ffi interface. If you have ffi array you should use 0-based indexing, but when you use Lua array you should use 1-based. In other it is matter of taste.Displode
0 is correct if you care at all about modular arithmetic: m*n%n = 0.Backslide
If you must, this is also valid: t = { [0] = "a" }; print(t[0])Fraud
An index is an offset from start, not the actual "label" of an item in a list. So the first element has offset 0 ence it's index is 0. Modular arithmetic, matrix multiplications, and many other algorithms are simpler if coded using the 0-index approach... make use of the Occam principle -> 0-index base is to be preferred (at least in a programming environment)Latoyia
default scope is also global... which is like saying that a traffic light controller, in case of failure, commands all traffic lights to go green instead of red...Latoyia
There are clearly advantages to 1- or 0- based indexing, but in Lua's case, 0- based would have been a better choice; look at Wireshark. Lua is used to extend large applications and expose internal data structures. Wireshark, for example, has to deal with lots of networking data structs, most of which use 0- based indexing (like the TCP segment field). Because those data structs already use 0- based indexing, it only makes sense for Wireshark's userdata types like Tvb, TvbRange, and ByteArray to use 0- based indexing. But then you have an awful mix of 0- and 1- based indexing.Hygeia
If Lua's principal role in life wasn't interfacing and extending software written in other languages, I think 1- based indexing would be every bit as good as 0- based. As things are, though, 1- based indexing was a mistake.Hygeia
Just to share a point in favor of the 0-indexing, consider when iterating over array indices using modulus: int a[] = { 5, 7, 8, 3 }; for( int i=0; i<32; i++ ){ do something with a[i%4] } Very simple, compared to the ugly a[1 + i%4]Prevent
The default global scope is intentional, and with good reason, because " without local declarations, you cannot say where the variable is local to." (RiciLake, Lua User's Wiki). But I'll agree, the 1-based indexing doesn't have nearly as good a rationale by comparison.Parsee
People keep pointing to Dijkstra's argument in favour of counting from 0 to favour 0-based indexing, but his arguments are frankly terrible. He spends the first 3 paragraphs without mentioning counting from 0 at all, just to build up to "0 <= i < N looks a bit nicer than 1 <= i < N+1". His first 2 arguments in favour of convention a) aren't even relevant in the context of indexing. His argument about specifying ranges using only natural numbers presupposes that specifying a range that starts with 0 is desirable, which is circular with his ultimate conclusion.Big
zero-based indexing takes 5 minutes to get used to. one-based indexing is a lifetime of hassle when doing anything numerically related to the index.Hygienic
Lua tables actually do not "start" anywhere - they're not really ordered. You can use tables with a 0-based index, and that's OK, so long as you understand: a) the standard libraries use 1-based counting, and b) how then length (#) operator works. TL;DR: lua "arrays" are not arrays but just tables like any other, length is defined as the unique border of a sequence, a sequence is a table with a unique border, a border is a table key b for which b is == 0 or b ~= nil, b is a number, and t[b+1] == nil. Make your peace with that. =) Also strongly consider using 1-based counting in Lua.Frisbie
If you really need 0-based indexing because you can't live w/o it - just make a function that creates "0-arrays" which have a metatable __get and __set that do n-1 indexing, and a __len which does the right thing as well (you have to check if the border is 0, etc). Don't expect Lua programmers to like/accept your code, however, if you do.Frisbie
Dijkstra's paper is worth reading as an indication of how and why he thought zero-based arrays were better --- and why it doesn't generalize to language design, and to modern hardware and softwareGeronto
@Frisbie From a users point of view, yes a table is just a map with keys pointing to values. In the underlying representation however, there is definetly used an array part and a record part of the array. In C you can actually request a reserved size for the array part. So yes Lua does have arrays.Popeyed
@Frisbie Also to make a correct metatable w/ 0 indexing you can't use __set and __get since those metamethod, just don't exist. __newindex and __index exist though. However those only get called if an index is missng or are newly created. So you will have to create a proxy to a protected data structure.Popeyed
that Dijkstra paper is really biased by intentionally phrasing it as 0 <= i < N vs. 1 <= i < N+1 - somehow he insisted the ranges be bookended by asymmetric <= one side and < on the other. These are array indices, not PDFs and CDFs, so bounding it the way they do it in statistics make very little sense. If he's fair he would've written 0 <= i < N vs. 0 < i <= N, and one can see it comes down to a matter of preference……...Vacate
………...regarding those for(…; ….; …) loops, I write most of my awk for loops like ::::::::::::::::: ::::::::: for (x = 0; x++ < N; ) { …. } (since awk is also 1-based indexing) …. i don't see how that's any harder to read than the 0-based ones. If anything, it's eaiser to read, since this approach eliminated the need for the 3rd argument, and consolidated the index incrementing onto boolean condition in the middle.Vacate
U
203

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.

Unconditional answered 7/5, 2010 at 2:42 Comment(9)
This is just a historical, marketing reason. No rational reason, especially at current time. And it seems even you're trying to avoid 1-based indexing instead of utilizing it :)Shive
@Eonil actually avoiding explicit indexing reduces indexing errors.Choosy
@Eonil historic reasons are usually the relevant ones. You start with something, and then you can never change it, because it would break all existing code. Particularly bad for 0 vs. 1 indexing, since the way it breaks is pretty subtle.Jinnah
The difference is between going from 1 to Length and from 0 to length -1, but in a for loop the < length is much more handy and easier to read on the "weirdo 0-based languages". I confess when I see a loop iterating from 1, i immediately assume it starts from the 2nd element :SVermiculation
I thought it was the stupidest thing when I started playing around with it as part of a Minecraft mod called ComputerCraft, but given the historical precedent, I guess I can understand why it is the way it is. That said, do you happen to have a link handy where I can read more about this connection to Sol? I'm always curious about the background for a language I'm working with, even if I'm not using it for anything serious.Till
There is a paper in the History of Programming Languages conference, and also lua.org/history.htmlUnconditional
That doesn't mean Lua needed to keep that particular aspect of Sol though.Giacometti
Lua does not have one-based arrays. Lua does not have arrays. See above comment on the question.Frisbie
Nobody remembers that Fortran and Basic also used 1-based arrays?Christoffer
F
59

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.

Further answered 7/5, 2010 at 2:15 Comment(0)
P
16

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.

Providence answered 7/5, 2010 at 1:58 Comment(2)
Possible justification: C only did it because an array is basically just a pointer and array[0] == array + 0;, and 1-based counting is more natural when array is really a hash table.Behka
Lua indices are actually indices. In C when you say index what you really mean is an offset.Salzhauer
S
10

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.

Shuttlecock answered 6/8, 2012 at 9:5 Comment(4)
While this is nice, it was not the reason for starting at 1.Culminate
That's not better symmetry. Now you have a situation where -3, -2, -1, 1, 2 and 3 are valid indices, but not 0!Moscow
how is it not better symmetry? Just because one index is completely invalid (doesn't point to either end, which I agree isn't great if you so happen to need EVERY index up to the integer limit... whatever that is for Lua) doesn't mean the symmetry isn't thereTill
-1 is not a valid array index in languages that have arrays (ie. not Lua). So the notion of "symmetry" between array indexes doesn't hold water.Frisbie
A
6

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
Adiell answered 22/12, 2017 at 11:38 Comment(2)
Is there a way to make ({'a', 'b'})[1] evaluate to 'b' not 'a' though? That seems built-in to me.Fabaceous
({[0] = 'a', 'b'})[1]Adiell
Z
5

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.

Zonate answered 3/2, 2021 at 10:59 Comment(1)
There are no "arrays" in Lua, and so no choice about 0 vs 1 array "base index" was made during language design or implementation. At all. See my comment on the question for details.Frisbie
S
-2

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]))
Savdeep answered 7/11, 2016 at 9:12 Comment(0)
T
-3

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.

Tetrapody answered 24/11, 2010 at 14:18 Comment(2)
Even if this is true, it is not at all relevant to how Lua was designed.Culminate
yeah, no, this answer is highly suspect. Please provide a source for this statement about Portugal's legal system as it relates to Lua, as I'm not even close to seeing and understanding the relevance.Till
B
-19

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.

Balikpapan answered 6/12, 2011 at 9:12 Comment(5)
I don't get the concept of a table being valued 0. A table can have a length of 0. But that's independent of the choice of first index. I don't care about minor grammar mistakes, but I simply don't understand the point of your answer, which is why I downvoted.Jinnah
thats what i ment, a table cant be hold with a 0 index or value, since we use it as an empty table <,< when you have something this something its represented from 1,"n" so when you have nothing, your empty of something, wich leads us to a cero, but the cero dosnt count, lua its a lenguage that comes practical, you dont go outside and tell your friends you know what i have 0 songs of that artists, eigther you have some, or you dont. the point its table = {} thats cero an empty tableBalikpapan
An array that uses the index 0 as only element is still not empty. In fact lua supports this, it's just not the default convention.Jinnah
yup i agree with you, on some other lenguages, but not lua, lua index 0 dosnt exist, so we can imagine it like an empty = 0, or thats how i picture it, even when you can force the index to be 0, it wont work with the table values #table wont read a 0 index, so my answer its still that lua its basicly made like a regular event, now if they intend this or not its not really relevant you wont write the hole code again, and we cant do anything about it :/, i still belive that its fair to say that in lua an empty table has a 0 indexBalikpapan
I don't think you are getting negative rep for grammar. That's easy enough for people to edit to help you fix. The problem is your answer doesn't seem to be coherent even in its intent. What does the length of a table have to do with the choice of first index? That seems to be your entire argument: it's length equals its last index? If you ever come back to SO, you should take another look at this one. I'm sure after 10 years you'll understand why everyone was so hard on it. Sometimes I want to kick myself over answers I gave 5 years ago so... yeahTill

© 2022 - 2024 — McMap. All rights reserved.