Reputation: 653
I've seen in several places that people put at the top of their init.lua
: local vim = vim
. What is the purpose of this? I could understand aliasings like local v = vim
or local g = vim.g
but it appears like local vim = vim
doesn't do anything.
Upvotes: 6
Views: 592
Reputation: 11171
local name = name
is called a localization. There are multiple good reasons to localize variables:
Recall that for environmental (usually global) variables, name
is just syntactic sugar for _ENV.name
which in turn is syntactic sugar for _ENV["name"]
; acessing a local variable on the other hand is practically a single array access where Lua knows the array index at compile-time (it's either an upvalue or a local, which get stored in different arrays; upvalues of functions are slightly slower).
The array/"register" access will be faster than accessing the hash part of _ENV
and searching for "name"
(hash map lookup is slower than array access). Technically Lua even has to first check the (implicit) _ENV
upvalue (called "function environment" in Lua 5.1 / LuaJIT) to see which table to index.
In conclusion, local variables / upvalues are usually faster than environmental variables; JIT-compilers like LuaJIT might optimize this out, but even LuaJIT has to consider the possibility that _G.vim
may be modified, which brings us to our second point:
it appears like
local vim = vim
doesn't do anything
For the most part this is correct, but not quite: local vim = vim
means "get the vim
environmental (global) variable at the time this line of code is executed (the load time of the script if it's at the top), then store it in a 'private' variable"; without this line, later modifications of the environment (e.g. vim = nil
) outside of the script will have an effect because the environment is reindexed. With this line, you get to keep your reference to the vim
table no matter what happens later on, which also provides an assurance to Lua / presumably also LuaJIT that it won't change later on.
Additionally, if a metatable is set on _G
, _G.name
can return different results at different times based on the metamethod that return
s it. Again localizing ensures that your local variable doesn't change (unless you explicitly change it).
Localizing all used environmentals makes your dependencies explicit, akin to the "import" statements of other languages. In Lua, require
is not consistently used; some libraries are simply part of the global environment _G
, such as vim
in your example, whereas others have to be require
d. For require
, you'd use local lib = require("lib")
, then why not consistently do this for global variables as well, rather than redoing the indexing operation every time?
This will probably rarely be the reason, but it's worth noting.
If you set a custom environment for your chunk, you will have to find a way to keep accessing global variables.
There are two options for this:
One is to use a metatable with __index = _G
(or whatever the parent environment is to be), but this is inefficient and unpredictable; it practically means your environment inherits everything from its parent environment, so e.g. _ENV.math.floor
would be _G.math.floor
, which may be considered dirty if you want to export your _ENV
as API table of a module.
The other is to localize all global variables you use. This doesn't have the drawbacks of the first solution; it is more performant, more predictable, and doesn't force you to have your environment inherit from the parent environment.
Upvotes: 8