Search code examples
luaneovim

Why do people put local vim = vim at the top of init.lua


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.


Solution

  • local name = name is called a localization. There are multiple good reasons to localize variables:

    Performance

    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:

    Semantics

    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 returns it. Again localizing ensures that your local variable doesn't change (unless you explicitly change it).

    Code Quality

    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 required. 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?

    Environment Changing

    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.