Eventually you end up in a place where it's beneficial to have converter functions that show up in the call stack frames so that you can keep track of whether the index is in the right "coordinate index system" (for lack of a better term) for the right language.
One can read through “mystdlib” part of any meaningful Lua-based project to see it. Things you’ll likely find there are: NIL, poor man’s classes, __newindex proxying wrapper, strict(), empty dict literal for json, “fixed” iteration protocols.
You don’t even have to walk too far, it’s all right there in neovim: https://neovim.io/doc/user/lua.html
Why numbering should start at zero. -- Dijkstra
"when starting with subscript 1, the subscript range 1 ≤ i < N+1; starting with 0, however, gives the nicer range 0 ≤ i < N"
So it's "nicer", ok! Lua has a numeric for..loop, which doesn't require this kind of range syntax. Looping is x,y,step where x and y are inclusive in the range, i.e. Dijkstra's option (b). Dijkstra doesn't like this because iterating the empty set is awkward. But it's far more natural (if you aren't already used to languages from the 0-indexed lineage) to simply specify the lower and upper bounds of your search.
I actually work a lot with Lua, all the time, alongside other 0-indexed languages such as C and JS. I believe 0 makes sense in C, where arrays are pointers and the subscript is actually an offset. That still doesn't make the 1st item the 0th item.
Between this, and the fact that, regardless of language, I find myself having to add or subtract 1 frequently in different scenarios, I think it's less of a deal than people make it out to be.
If the word for word same argument was made by an anonymous blogger no one would even consider citing this as a definitive argument that ends the discussion.
If you then even consider the simple case of nested arrays, I think it becomes really difficult to defend 1-based indexing as being cognitively easier to manipulate, as the unit of "index" doesn't naturally map to a counting number like that... if you use 0-based indexes, all of the math is simple, whereas with 1-based you have to rebalance your 1s depending on "how many" indexes your compound unit now represents.
To me 1 based indexing is natural if you stop pretending that arrays are pointers + index arithmetics. Especially with slicing syntax.
It's one of the things that irked me when switching to Julia from Python but which became just obviously better after I made the switch.
E.g. in Julia `1:3` represents the numbers 1 to 3. `A[1]` is the first element of the array, `A[1:3]` is a slice containing the first to third element. `A[1:3]` and `A[4:end]` partitions the array. (As an aside: `For i in 1:3` gives the number 1, 2, 3.)
The same sentence in python:
`1:3` doesn't make sense on its own. `A[0]` is the first element of the array. `A[0:3]` gives the elements `A[0], A[1]` and `A[2]`. `A[0:3]` and `A[3:]` slice the array.
For Python, which follows Dijkstra for its Slice delimiters, I need to draw a picture for beginners (I feel like the numpy documentation used to have this picture, but not anymore). The Julia option requires you to sometimes type an extra +1 but it's a meaningful +1 ("start at the next element") and even beginners never get this wrong.
That said, it seems to me that for Lua, with the focus on embedding in the C world, 0 index makes more sense.
t={}
t[#t+1] --> t[1] DONE!
t[#t==0 and 0 or #t+1]
Now, in order to fix this (or achieve the same behavior as #t+1), the length operator must return -1, which would be ridiculous. its empty, and we have a perfect representation of emptiness in math "0".This is also true in awk as well, nobody ever whines about awk "arrays" being 0
The real gripes should be globals by default and ... nothing. Lua is wonderful.
I get you are taking the piss but ~= is just as logical as != being the symbols for: "not equals", if you've been exposed to some math(s) as well as ... well, ! means factorial, doesn't it?
Syntax is syntax and so is vocabulary! In the end you copy and paste off of Stack Exchange and all is golden 8)
[attr~=value]
Represents elements with an attribute name of attr whose value is a whitespace-separated list of words, one of which is exactly value.
[1] https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_s...I'm a big fan of Lua, including for the reasons you mention. I suspect the reason this one thing is always brought up is twofold: it's easy to notice, and it's very rare these days outside of Lua (if you consider VB.NET to be a legacy language, anyway). Other criticisms take more effort to communicate, and you can throw a rock and hit ten other languages with the same or similar issues.
To be fair, Brendan Eich was making a scripting language for the 90's web. It isn't his fault Silicon Valley decided that language needed to become the Ur-language to replace all application development in the future.
IIRC, Eich was quite influenced by Python's design. I wish he'd just used Lua - would likely have saved a lot of pain. (Although, all that said, I have no idea what Lua looked like in 1994, and how much of its design has changed since then.)
If you don't know what Lua was like then, don't wish that I'd "just used Lua".
Other issues include Netscape target system support, "make it look like Java" orders from above, without which it wouldn't have happened, and more.
It sounds like you're saying Yoz got the sequence of events wrong, and that MILLJ was a necessary part of getting scripting in the browser? I sort of had the impression that the reason they hired you in the first place was that they wanted scripting in the browser, but I wasn't there.
I don't think Lua was designed to enforce a security boundary between the user and the programmer, which was a pretty unusual requirement, and very tricky to retrofit. However, contrary to what you say in that comment, I don't think Lua's target system support or evolutionary path would have been a problem. The Lua runtime wasn't (and isn't) OS-dependent, and it didn't evolve rapidly.
But finding that out would have taken time, and time was extremely precious right then. Also, Lua wasn't open-source yet. (See https://compilers.iecc.com/comparch/article/94-07-051.) And it didn't look like Java. So Lua had two fatal flaws, even apart from the opportunity cost of digging into it to see if it was suitable. Three if you count the security role thing.
Yes, the Sun/Netscape Java deal included MILLJ orders from on high, and thereby wrecked any Scheme, HyperTalk, Logo, or Self syntax for what became JS.
Lua differed a lot (so did Python) back in 1995. Any existing language, ignoring the security probs, would be flash-frozen and (at best) slowly and spasmodically updated by something like the ECMA TC39 TG1 group, a perma-fork from 1995 on.
Flash-freezing Lua might not have been so bad; that's basically what every project using Lua does anyway. And by 01995 it was open source.
In case anyone is interested, here's a test function from the Lua 2.1 release (February 01995):
function savevar (n,v)
if v == nil then return end;
if type(v) == "number" then print(n.."="..v) return end
if type(v) == "string" then print(n.."='"..v.."'") return end
if type(v) == "table" then
if v.__visited__ ~= nil then
print(n .. "=" .. v.__visited__);
else
print(n.."=@()")
v.__visited__ = n;
local r,f;
r,f = next(v,nil);
while r ~= nil do
if r ~= "__visited__" then
if type(r) == 'string' then
savevar(n.."['"..r.."']",f)
else
savevar(n.."["..r.."]",f)
end
end
r,f = next(v,r)
end
end
end
end
It wouldn't have been suitable in some other ways. For example, in versions of Lua since 4.0 (released in 02000), most Lua API functions take a lua_State* as their first argument, so that you can have multiple Lua interpreters active in the same process. All earlier versions of Lua stored the interpreter state in static variables, so you could only have one Lua interpreter per process, clearly a nonstarter for the JavaScript use case.The Lua version history https://www.lua.org/versions.html gives some indication of what a hypothetical Sketnape Inc. would have been missing out on by embedding Lua instead of JavaScript. Did JavaScript have lexical scoping with full (implicit) closures from the beginning? Because I remember being very pleasantly surprised to discover that it did when I tried it in 02000, and Lua didn't get that feature until Lua 5.0 in 02003.
Which remains one of the most baffling decisions of all time, even to this day. Javascript is unpleasant to work with in the browser, the place it was designed for. It is utterly beyond me why anyone would go out of their way to use it in contexts where there are countless better languages available for the job. At least in the browser you pretty much have to use JS, so there's a good reason to tolerate it. Not so outside of the browser.
The pressure to evolve JS in a more fair-play standards setting rose and fell as browser competition rose and fell, because browser vendors compete for developers as lead users and promoters. Before competition came back, a leading or upstart browser could and did innovate ahead of the last JS standard. IE did this with DHTML mostly outside the core language, which MS helped standardize at the same time. I did it in Mozilla's engine in the late '90s, implementing things that made it into ES3, ES5, and ES6 (Array extras, getters and setters, more).
But the evolutionary regime everyone operated in didn't "decide" anything. There was and is no "Silicon Valley" entity calling such shots.
Oh come on, you understand full well that they're referring to the wider SV business/software development "ecosystem".
Which is absolutely to blame for javascript becoming the default language for full-stack development, and the resulting JS-ecosystem being a dysfunctional shitshow.
Most of this new JS-ecosystem was built by venture capital startups & tech giants obsessed with deploying quickly, with near-total disregard for actually building something robustly functional and sustainable.
e.g. React as a framework does not make sense in the real world. It is simply too slow on the median device.
It does, however, make sense in the world of the Venture Capital startup. Where you don't need users to be able to actually use your app/website well. You only need that app/website to exist ASAP so you can collect the next round of investment.
Companies including Bloomberg and Microsoft (neither in or a part of Silicon Valley), also big to small companies all over the world, built on JS once Moore’s Law and browser tech combined to make Oddpost, and then gmail, feasible.
While the Web 2.0 foundations were being laid by indie devs, Yahoo!, Google, others in and out of the valley, most valley bigcos were building “RIAs” on Java, then Flash. JS did not get some valley-wide endorsement early or all at once.
While there was no command economy leader or bureaucracy to dictate “JS got on first but it is better to replace it with [VBScript, likeliest candidate]”, Microsoft did try a two-step approach after reacting to and the reverse-engineering JS as “JScript”.
They also created VBS alongside JS, worked to promote it too (its most used sites were MS sites), but JS got on first, so MS was too late even by IE3 era, and IE3 was not competitive vs. Netscape or tied to Windows. IE4 was better than Netscape 3 or tardy, buggy 4 on Windows; and most important, it was tied. For this tying, MS was convicted in _U.S. v. Microsoft_ of abusing its OS monopoly.
Think of JS as evolution in action. A 2024-era fable about the Silly Valley cartel picking JS early or coherently may make you feel good, but it’s false.
He was, and he doesn't deserve the full blame for being bad at designing a language when that wasn't his prior job or field of specialization.
But Lua is older so there's this element of "it didn't need to be this bad, he just fucked up" (And Eich being a jerk makes it amusing to pour some salt on that wound. Everyone understands it's not entirely serious.)
It is very funny how this is just the one sole criticism that always gets brought up. Not that other problems don't exist, but they're not very talked about.
Lua's strength as a language is that it does a lot quite well in ways that aren't noticeable. But when you compare things to the competition then they're quite obvious.
E.g. Type Coercion. Complete shitshow in lots of languages. Nightmare in Javascript. In Lua? It's quite elegant but most interestingly, effortlessly elegant. Very little of the rest of the language had to change to accomodate the improvement. (Excercise for the reader: Spot the one change that completely fixes string<->number conversion)
Makes Brendan Eich look like a total clown in comparison.