Lua 5.1 had something similar, but the implicit environment was per-function.
A common pattern in Lua is to change _ENV to an empty table with a __newindex meta-method that writes-through to the real global environment, and an __index meta-method that throws an error if the key (i.e. global symbol) doesn't exist. You can fancy and have an __index meta-method that that throws an error string with suggestions for a possibly misspelled symbol, similar to clang or GCC compiler diagnostics.
> Everything is a table and accessing unset variables is accessing the table (named _G) holding all global variables.
Before you said this, I had no idea about that. Because it's not like the tutorials are talking about the underlying implementation for this stuff, just like how Java tutorials don't usually go deep in explaining how bytecode works, or how the JVM can be used to interoperate with other languages.
Lua is an incredibly simple and elegant language. All the myths and bike-shedding on Stack Overflow and elsewhere can only lead you astray. For exceptional situations, use the mailing-list. The authors and almost all experts are on the mailing-list and will be quick to correct errors. (Everybody is wrong sometimes, even the authors! But you need enough experts in one place to be paying attention, and the only such place is the mailing-list.)
Another thing to keep in mind is that Lua maintains strict feature symmetry between what's possible in Lua code, and what's possible from the Lua C API. This is important to understand if you want to have a good mental model of the language and why it's designed the way it is. If you're not a C programmer or haven't heavily used the Lua C API, many of Lua's choices may seem arbitrary, especially coming from other languages where their C ABI and FFI interfaces are mostly an afterthought or don't otherwise constrain the in-language semantics. Most "better than Lua" projects are written by people without a sufficient appreciation for this aspect of Lua's design.
> This is important to understand if you want to have a good mental model of the language and why it's designed the way it is.
I want to have a good mental model of the code I write, and how that works, not the underlying language mechanisms themselves.
I've been picking up Kotlin, and I hardly know anything of how it works under the hood, other than whatever it 'inherits' from being a JVM language, and so far it's been totally fine. Why should I need to care about how the sausage is made?
Are you the nine-year-old? I was responding to a criticism you made regarding your understanding. Are online tutorials for children learning their first programming language supposed to explain the rationale behind the language design? If you want the latter don't use children's tutorials, or in the case of Lua, any tutorials, because the official material is at least as easy to understand, and infinitely more reliable and accurate.
If you've worked a bit with Lua, it's actually pretty reasonably and consistent: Everything is a table and accessing unset variables is accessing the table (named _G) holding all global variables. So
assuming a isn't a local variable, is essentially the same as As accessing unset keys within a table returns nil, doing so for globals makes it consistent. Also _G._G == _G :-)