i know you're able to do constant variables in lua now with <const>
, but they seem to only work with local variables:
local myNumber <const> = 10 -- This works perfectly fine
myGlobalNumber <const> = 10 -- This causes an error
Is it possible to have constant global variables as well?
myGlobalNumber <const> = 10
The point of the <const>
local variable attribute is to allow Lua to check, at "load" time (when you call dofile
/ load
/ require
or similar), whether a local variable is not being mutated - that is, whether the only assignment is the initial one at declaration time. It is a tool to help programmers (1) express intent (2) get slightly more "load time" checking than just syntactic checks.
This works for local
variables precisely because they are local. They are visible only within function scope. This means Lua has all the information it needs when you load a "chunk" of code (effectively a function body) to check whether it abides by the static (load time) rules of <const>
.
"Globals" / "environmental variables" (as I like to call them) are effectively just syntactic sugar for accessing fields in the _ENV
(usually _G
) table. As such, they are much more dynamic than local variables. You could do _G[some .. complex .. expression] = 42
, for example. With global variables, just as with any other table fields, Lua does not have all the information it needs at load time. To begin, it does not even know which fields your code will set or get. Even if it knew this, or limited itself to the <name>
syntax, that would still be insufficient. Consider loading a file where a certain global variable that was not set yet is used (perhaps in some callback where the author knows it will be available in time). Lua can not warn about this at the time the file is loaded. (It could, at best, try to warn when the file containing the conflicting constant definitions was loaded, then warn when subsequent files are loaded.)
As ESkri has said, you can implement run-time checks to guard against accessing constant global variables via a metatable. That could look something like this:
local constants = {pi = math.pi}
setmetatable(_G, {__index = constants, __newindex = function(_, key) error("attempt to change constant global variable " .. key) end})
print(pi) -- runs fine
pi = 3 -- errors
However, this is probably a bad idea:
Instead, I would recommend the use of static analysis tools such as Luacheck, which lets you specify [read-only global variables in its configuration file, and also supports a new read globals
inline option to add read-only global variables, similar to a "constant" definition. Example:
-- luacheck: globals pi
pi = math.pi
-- luacheck: new read globals pi
pi = 3
it should be noted that while options are limited in scope to files, the read_global
configuration field is per-"project" (folder) you're running Luacheck in. To establish pi
as a read-only global project-wide, you could set read_globals = {"pi"}
, then use -- luacheck: globals pi
to make an exception where pi
is defined (followed by -- luacheck: new read globals pi
to revoke that exception afterwards).