In general using array indexes as foreign keys should always be considered carefully.
And if all you will be doing is iterating then the starting index doesn't really matter (unless you copy paste loop logic, which is a problem in itself)
Consider what happens when you sort your array, or delete or insert an item in the middle, or start. Now all your indexes have changed.
React had this issue, and this is why they had to add stable "key" to collections so that when you mutate a sequence of <li/> items for example, it doesn't get confused which is which.
EDIT: Other than the obvious
Using these languages for large projects is where the trouble starts: as they push you towards bad solutions that we know are bad for many decades. You need clear description of how to avoid these pittfals, or your growing codebase slowly becomes unmanageable.
I ended up ditching a growing Lua codebase for this reason. Get out before it gets to big to get out.
If there actually is a correlation between high level languages and "trouble", it may be just because a high level language lets a less experienced developer (or team of developers) get farther than they otherwise would in some lower level language, i.e. the more cumbersome nature of a lower level language forces you to follow best practices earlier or the whole thing never gets off the ground, while the same sloppy devs + a higher level language might actually get as far as shipping something.
Whether that is ultimately better is debatable, but the problem is more how the tool is being used than something inherent in the tool itself.
This is a really good point that I didn't realize before - sure, languages like bash and Lua and Tcl might scale very poorly to large codebases, but because they're more expressive than some other languages (coughjavacough), you might be able to implement the functionality you need without needing a large codebase in the first place.
Teal has an advantage that the typed language can be translated into Lua at runtime so during development it allows for quick prototyping and adding types when the amount of types becomes substantial. But its type system is less powerful than that of TypeScript.
There are dyn typed langs with langs with nice designs. I like Ruby and IOScript. All lisp-like languages. And there are several dyn typed fit-for-embedded langs implemented in Rust that are very promising. This is very much my own opinion, I know. But reading the article's "cons of Lua" I immediately remembered my fight with that language.
Personally I prefer typed languages nowadays. The stronger the better, as long as there is good IDE support.
“Look, we need you to implement this feature within the next 24 hours.”
“Based on my scrum analysis, I need about a week to implement it.”
“Sorry, if it’s not done within the next 24 hours, you will be out of a job.”
“OK....”
At which point, we get a hideous rush job. I have seen this happen time and time again. There is no language in the world which isn’t going to be able to force clean, manageable code under these kinds of circumstances, which alas can and do happen too often in the caffeine and work obsessed tech culture.
Just a feeling, but coding with them feels like they are refactor-optimized langs.
Strong typed code is much easier to refactor.
Gradual typing has been improving (might not be the only way but still)
For me the ideal would be a language with the expressiveness and fast dev times of Python, and then type information would be collected from actually running the program during development and would gradually shift from auto-generated type hints to more concrete type declarations that could be enforced but that would also assist in compilation & optimization.
The type gathering from use would be nice.
The fast dev times, as in quick "edit -> run -> try" loops, it what I find most attractive of the dyn langs nowadays. And gradual typing might be a way to get there, although I think it is not needed (some strong typed langs have decent hot code reload).
https://github.com/yuin/gopher-lua Lua in Go
https://github.com/fengari-lua/fengari Lua in Javascript
Back in the late 80s before Python and Lua were released the following decades, TCL made sense, as it was the only freely available embedable language.
Python's larger and more complete (and I'd argue a better language then Lua), but Lua's compact and very fast as it's a register-based bytecode VM (and luaJIT exists which is even faster) (although if you don't use the 'local' keyword on variables, it's then quite a bit slower as it no longer uses stack-based variables, so the code can end up being more verbose to make it fast), so games commonly used Lua for scripting/gameplay as it was easy to integrate.
Back in 2004 or 2005, Firaxis decided to use Python as their embedded scripting language. They used something called “Boost Python”, a then reasonably easy to embed fork of Python, to embed Python2 in their Civilization 4 gaming engine.
Soon after this, Boost Python got abandoned and Firaxis ended up having to use an outdated version of Python by the time they released their final Civilization 4 expansion.
For Civilization 5, Firaxis instead used Lua, since they wanted an actively maintained code base.
For my own “embed a scripting language in a DNS server” project, I went with a slightly modified Lua 5.1. The entire DNS server, including the Lua scripting engine, is a 103,936 byte sized Windows service. The stack was a little hard to grok at first, but I was able to fairly quickly get used to it and have a Lua script set up configuration for the server, as well as parse DNS queries. [1]
To Python’s credit, the Python2 code used in Civilization 4 is 100% compatible with the final 2019 release of a Python2 interpreter, to the point that I can run map scripts for Civilization 4 -- compiled for x86/32-bit -- on a 64-bit ARM Raspberry Pi and have them generate the exact same maps. Useful when I wanted a particular kind of map for a Civ4 mod, and had to iterate through 300 different random seeds on my Raspberry Pi to find the desired kind of map. After about a month, I had over 180 map seeds meeting my criteria.
[1] https://github.com/samboy/MaraDNS/tree/master/deadwood-githu... for the record
Lua made inroads into the game dev community in particular thanks to LuaJIT. Despite it actually being a fork of Lua that hasn't kept up with changes in the base language, LuaJIT remains popular for its speed.
In practice, it is hard to embed and we get the GIL disadvantages, so that is not working out so fine.
I also evaluated Python and Lua. As others have noted, Python appears to be a right royal pain to embed. I actually had more experience with Lua prior to that project, but that experience leads me to believe that Lua is, generally, the wrong language.
Looking back on the project, I would not hesitate to do the same thing again, ideally as open source so that other Go projects can embed a scripting language. It got the job done, and did it well. Non-programmers on our team were able to write both configuration and logic successfully & productively, and apparently enjoyed the experience. Tcl itself ended up being a pleasure to use. While I personally would have enjoyed something like Embeddable Common Lisp, I think that would have been to much to ask of the rest of the team.
Interestingly, the four languages Lua, Python, Tcl and Lisp each can be said to take one idea and run with it. Lua is everything-is-a-hash-table (well, almost everything); Python is everything-is-an-object; Tcl is everything-is-a-string; and Lisp is everything-is-a-list (well, in theory: in practice it is really everything-is-an-object). I don’t know if this says anything deep about scripting languages, but it is at least interesting — right?
[1] https://en.wikipedia.org/wiki/List_of_applications_using_Lua
To my knowledge, you can't do that with Python. I don't know about TCL though.
It has its quirks yes, but if I need to add scripting to a software, I'd consider Lua before considering writing a DSL, simply because you can pretty much embed Lua's source in your C/C++ software as a static library[0].
The stack-based approach makes it so easy to interact with C/C++, and I've been looking at the Rust bindings[1] recently out of curiosity, looks promising.