Tech Note | Special Considerations Regarding Scoping in the Q-SYS Implementation of Lua

Gain insights into effective scoping practices in Lua for optimizing Q-SYS implementations, enhancing performance and reliability.

Updated at August 27th, 2026

Information


Because Q-SYS does not use Lua in the standard implementation, some considerations must be made when scoping out a system design using Lua. This article breaks down the differences between standard and the Q-SYS implementations of Lua.

Scoping in Standard Lua Environments

Lua is an embedded extension scripting language. The scoping intuitions of formal compiled languages do not hold in Lua. Instead, “By default, variables in Lua are global. All local variables must be declared as such. Unlike global variables, a local variable has its scope limited to the block where it is declared. A block is the body of a control structure, the body of a function, or a chunk.” – Ierusalimschy, Roberto. Programming in Lua. 4th ed. Lua.Org, 2016, 67.

Below are some basic implications/guidelines of Lua’s scoping paradigm.

  1. Implicitly, all variables (tables, functions, objects, etc.) are global by default regardless of location in code of first use.
  2. Local variables must be explicitly declared as local.
  3. Global variables can be created anywhere, even inside functions.
  4. Arguments to functions are necessarily local to that function.

Scoping in the Q-SYS Implementation of Lua

Ierusalimschy offers the following suggestions for Standard Lua, “It is good programming style to use local variables whenever possible. Local variables avoid cluttering the global environment with unnecessary names; they also avoid name clashes between different parts of a program. Moreover, the access to local variables is faster than to global ones. Finally, a local variable vanishes as soon as its scope ends, allowing the garbage collector to release its value.” - Ierusalimschy, Roberto. Programming in Lua. 4th ed. Lua.Org, 2016, 68.

However, Q-SYS does not implement Lua in the Standard way. Therefore, most of Ierusalimschy’s suggestions are not applicable in Q-SYS Lua scripting. Instead, Q-SYS implements Lua with a sandboxing methodology. The sandboxing enables Q-SYS to implement certain security features of the system and to include the “Q-SYS Extensions to Lua” into the scripting environment.

An effect of Q-SYS’s sandboxing is that each scripting component (Control Script, Block Controller, Text Controller, Plugin, etc.) executes independently of each other. Stated alternatively, there is no shared global space between the scripting components. Therefore, the concern for “cluttering the global environment” is essentially moot.

Additionally, Ierusalimschy’s insight regarding faster access to local variables is conceptually sound. For example, declaring “local sine = math.sin” places a copy of the function in the stack which can be accessed in linear time, whereas, simply referencing math.sin would require two lookups to ultimately access the function. However, in actual practice in Q-SYS scripting, no significant statistical optimization has been observed.

Lastly, Ierusalimschy’s awareness of the garbage collector is the most instructive for the Q-SYS Lua programmer. As he states, “a local variable vanishes as soon as its scope ends.” While garbage collection is not actually as simple as Ierusalimschy paints it here, it is sufficiently clear that the Q-SYS Lua programmer should exercise caution with local variables. The use of the keyword “local” by the Q-SYS Lua Programmer is an expression of their intent that the variable (table, function, object, Q-SYS Extensions to Lua, etc.) is to be considered programmatically ephemeral and therefore subject to garbage collection. As a corollary, variables that are to be programmatically persistent should never be declared as “local,” since global variables are not subject to garbage collection.

Scoping decisions align along these two basic principles:

  1. Local variables (tables, functions, objects, Q-SYS Extensions to Lua, etc.) are ephemeral and subject to garbage collection.
  2. Global variables are persistent and immune to garbage collection.

Recommended practices for scoping in Q-SYS’s Implementation of Lua.

  1. Variables that are ephemeral by nature may be declared local, if desired.
  2. Variables that are persistent by nature must not be declared local.
  3. Many Q-SYS Extensions to Lua must be considered persistent by nature and therefore should never be declared local, e.g., Timers, TcpSockets, etc. (Refer to the Help File’s page on Q-SYS Extensions to Lua for additional details.)