Matter AI | Code Reviewer Documentation home pagelight logodark logo
  • Contact
  • Github
  • Sign in
  • Sign in
  • Documentation
  • Blog
  • Discord
  • Github
  • Introduction
    • What is Matter AI?
    Getting Started
    • QuickStart
    Product
    • Security Analysis
    • Code Quality
    • Agentic Chat
    • RuleSets
    • Memories
    • Analytics
    • Command List
    • Configurations
    Patterns
    • Languages
      • Supported Languages
      • Python
      • Java
      • JavaScript
      • TypeScript
      • Node.js
      • React
      • Fastify
      • Next.js
      • Terraform
      • C#
      • C++
      • C
      • Go
      • Rust
      • Swift
      • React Native
      • Spring Boot
      • Kotlin
      • Flutter
      • Ruby
      • PHP
      • Scala
      • Perl
      • R
      • Dart
      • Elixir
      • Erlang
      • Haskell
      • Lua
      • Julia
      • Clojure
      • Groovy
      • Fortran
      • COBOL
      • Pascal
      • Assembly
      • Bash
      • PowerShell
      • SQL
      • PL/SQL
      • T-SQL
      • MATLAB
      • Objective-C
      • VBA
      • ABAP
      • Apex
      • Apache Camel
      • Crystal
      • D
      • Delphi
      • Elm
      • F#
      • Hack
      • Lisp
      • OCaml
      • Prolog
      • Racket
      • Scheme
      • Solidity
      • Verilog
      • VHDL
      • Zig
      • MongoDB
      • ClickHouse
      • MySQL
      • GraphQL
      • Redis
      • Cassandra
      • Elasticsearch
    • Security
    • Performance
    Integrations
    • Code Repositories
    • Team Messengers
    • Ticketing
    Enterprise
    • Enterprise Deployment Overview
    • Enterprise Configurations
    • Observability and Fallbacks
    • Create Your Own GitHub App
    • Self-Hosting Options
    • RBAC
    Patterns
    Languages

    Lua

    Lua is a lightweight, high-level, multi-paradigm programming language designed primarily for embedded use in applications. It is cross-platform, as the interpreter of compiled bytecode is written in ANSI C.

    Lua, despite being a lightweight and flexible language, has several common anti-patterns that can lead to performance issues, maintainability problems, and bugs. Here are the most important anti-patterns to avoid when writing Lua code.

    -- Anti-pattern: Implicit global variables
    function process_data()
      result = 42  -- Implicitly global!
      return result
    end
    
    -- Better approach: Use local variables
    function process_data()
      local result = 42  -- Explicitly local
      return result
    end

    Always use the local keyword when declaring variables. In Lua, variables are global by default, which can lead to unexpected behavior and name collisions.

    -- Anti-pattern: Global functions and variables
    function calculate_area(radius)
      return math.pi * radius * radius
    end
    
    function calculate_circumference(radius)
      return 2 * math.pi * radius
    end
    
    -- Better approach: Use modules
    local Circle = {}
    
    function Circle.area(radius)
      return math.pi * radius * radius
    end
    
    function Circle.circumference(radius)
      return 2 * math.pi * radius
    end
    
    return Circle

    Organize your code into modules instead of using global functions and variables. This improves maintainability and reduces the risk of name collisions.

    -- Anti-pattern: Inefficient table usage
    local list = {}
    for i = 1, 1000 do
      table.insert(list, i)  -- Inefficient for large lists
    end
    
    -- Better approach: Pre-allocate indices
    local list = {}
    for i = 1, 1000 do
      list[i] = i  -- More efficient direct assignment
    end

    Use direct index assignment instead of table.insert() when you know the index in advance. This is more efficient, especially for large tables.

    -- Anti-pattern: String concatenation in loops
    local result = ""
    for i = 1, 1000 do
      result = result .. "item " .. i .. "\n"  -- Creates many intermediate strings
    end
    
    -- Better approach: Use table.concat
    local parts = {}
    for i = 1, 1000 do
      parts[i] = "item " .. i
    end
    local result = table.concat(parts, "\n")

    Avoid concatenating strings in loops with the .. operator. Instead, collect strings in a table and use table.concat() at the end, which is much more efficient.

    -- Anti-pattern: No error handling
    function read_file(filename)
      local file = io.open(filename, "r")  -- Might fail
      local content = file:read("*all")
      file:close()
      return content
    end
    
    -- Better approach: Proper error handling
    function read_file(filename)
      local file, err = io.open(filename, "r")
      if not file then
        return nil, "Failed to open file: " .. (err or "unknown error")
      end
      
      local content, err = file:read("*all")
      file:close()
      
      if not content then
        return nil, "Failed to read file: " .. (err or "unknown error")
      end
      
      return content
    end
    
    -- Usage
    local content, err = read_file("data.txt")
    if not content then
      print("Error: " .. err)
    else
      -- Process content
    end

    Use proper error handling by checking return values and returning error messages. Lua functions often return nil plus an error message on failure.

    -- Anti-pattern: Incorrect numeric for-loop
    local t = {10, 20, 30, 40, 50}
    for i = 0, #t do  -- Starts at 0, but Lua tables are 1-indexed
      print(t[i])  -- t[0] is nil
    end
    
    -- Better approach: Correct indexing
    local t = {10, 20, 30, 40, 50}
    for i = 1, #t do  -- Lua tables are 1-indexed
      print(t[i])
    end

    Remember that Lua tables are 1-indexed by default. Start your numeric for-loops at 1 when iterating over sequential tables.

    -- Anti-pattern: Variables with too broad scope
    function process_data(items)
      count = 0  -- Global variable
      for i = 1, #items do
        if is_valid(items[i]) then
          count = count + 1
        end
      end
      return count
    end
    
    -- Better approach: Proper variable scoping
    function process_data(items)
      local count = 0  -- Local variable
      for i = 1, #items do
        if is_valid(items[i]) then
          count = count + 1
        end
      end
      return count
    end

    Keep variables in the smallest possible scope. Use local variables instead of global ones whenever possible.

    -- Anti-pattern: Inefficient table clearing
    function clear_table(t)
      t = {}  -- This creates a new table, doesn't clear the original
    end
    
    -- Better approach: Actually clear the table
    function clear_table(t)
      for k in pairs(t) do
        t[k] = nil
      end
    end

    Assigning a new empty table to a variable doesn’t clear the original table. Instead, set each key to nil to actually clear a table.

    -- Anti-pattern: Reinventing common patterns
    local Point = {}
    
    function Point.new(x, y)
      local self = {}
      self.x = x or 0
      self.y = y or 0
      
      function self.add(other)
        return Point.new(self.x + other.x, self.y + other.y)
      end
      
      return self
    end
    
    -- Better approach: Use metatables
    local Point = {}
    Point.__index = Point
    
    function Point.new(x, y)
      local self = setmetatable({}, Point)
      self.x = x or 0
      self.y = y or 0
      return self
    end
    
    function Point:add(other)
      return Point.new(self.x + other.x, self.y + other.y)
    end
    
    -- Even better: Operator overloading with metatables
    function Point.__add(a, b)
      return Point.new(a.x + b.x, a.y + b.y)
    end
    
    -- Usage
    local p1 = Point.new(1, 2)
    local p2 = Point.new(3, 4)
    local p3 = p1 + p2  -- Uses __add metamethod

    Use metatables to implement object-oriented patterns, operator overloading, and other advanced features in a clean and efficient way.

    -- Anti-pattern: Inefficient OOP pattern
    function create_person(name, age)
      local person = {}
      
      person.name = name
      person.age = age
      
      person.greet = function(self)
        return "Hello, I'm " .. self.name
      end
      
      person.have_birthday = function(self)
        self.age = self.age + 1
      end
      
      return person
    end
    
    -- Better approach: Prototype-based OOP
    local Person = {}
    Person.__index = Person
    
    function Person.new(name, age)
      local self = setmetatable({}, Person)
      self.name = name
      self.age = age
      return self
    end
    
    function Person:greet()
      return "Hello, I'm " .. self.name
    end
    
    function Person:have_birthday()
      self.age = self.age + 1
    end

    Use prototype-based OOP with metatables instead of creating new function objects for each instance. This is more memory-efficient and performs better.

    -- Anti-pattern: Not using closures effectively
    function create_counter()
      local counter = {count = 0}
      
      function counter.increment()
        counter.count = counter.count + 1
        return counter.count
      end
      
      function counter.get()
        return counter.count
      end
      
      return counter
    end
    
    -- Better approach: Use closures
    function create_counter()
      local count = 0
      
      return {
        increment = function()
          count = count + 1
          return count
        end,
        
        get = function()
          return count
        end
      }
    end

    Use closures to encapsulate state without exposing it directly. This provides better encapsulation and can be more memory-efficient.

    -- Anti-pattern: Poor module structure
    -- mymodule.lua
    function hello()
      print("Hello, World!")
    end
    
    function goodbye()
      print("Goodbye, World!")
    end
    
    -- These are now global functions
    
    -- Better approach: Proper module structure
    -- mymodule.lua
    local M = {}
    
    function M.hello()
      print("Hello, World!")
    end
    
    function M.goodbye()
      print("Goodbye, World!")
    end
    
    return M
    
    -- Usage
    -- local mymodule = require("mymodule")
    -- mymodule.hello()

    Structure your modules properly by returning a table of functions and values. This prevents polluting the global namespace.

    -- Anti-pattern: Unnecessary upvalues
    function create_functions()
      local functions = {}
      
      for i = 1, 10 do
        functions[i] = function() return i end  -- i is an upvalue
      end
      
      return functions
    end
    
    -- Better approach: Avoid unnecessary upvalues
    function create_functions()
      local functions = {}
      
      for i = 1, 10 do
        local value = i  -- Create a new local variable
        functions[i] = function() return value end
      end
      
      return functions
    end

    Be careful with upvalues in loops. Create a new local variable inside the loop to capture the current value, not the final value of the loop variable.

    -- Anti-pattern: Swallowing errors
    function process_file(filename)
      local file = io.open(filename, "r")
      if not file then
        print("Error opening file")
        return
      end
      
      -- Process file...
      file:close()
    end
    
    -- Better approach: Propagate errors
    function process_file(filename)
      local file, err = io.open(filename, "r")
      if not file then
        return nil, "Error opening file: " .. err
      end
      
      -- Process file...
      local result = file:read("*all")
      file:close()
      
      return result
    end
    
    -- Usage
    local result, err = process_file("data.txt")
    if not result then
      -- Handle error
      print(err)
    else
      -- Use result
    end

    Propagate errors up the call stack instead of handling them locally or swallowing them. This allows the caller to decide how to handle errors.

    -- Anti-pattern: Inefficient table traversal
    local t = {a = 1, b = 2, c = 3}
    
    for i = 1, #t do  -- This only works for array-like tables
      print(t[i])
    end
    
    -- Better approach: Use pairs for hash tables
    local t = {a = 1, b = 2, c = 3}
    
    for k, v in pairs(t) do
      print(k, v)
    end
    
    -- Use ipairs for array-like tables
    local arr = {10, 20, 30}
    
    for i, v in ipairs(arr) do
      print(i, v)
    end

    Use pairs() for traversing hash tables and ipairs() for traversing array-like tables. Don’t use the length operator (#) for non-sequential tables.

    -- Anti-pattern: Poor or no documentation
    function process_data(data, options)
      -- Implementation...
    end
    
    -- Better approach: Proper documentation
    ---Process data according to specified options
    ---@param data table The data to process
    ---@param options table|nil Optional settings with the following fields:
    ---                         - verbose (boolean): Whether to output verbose logs
    ---                         - max_items (number): Maximum number of items to process
    ---@return table The processed data
    ---@return string|nil Error message if an error occurred
    function process_data(data, options)
      -- Implementation...
    end

    Document your functions and modules properly. Include parameter descriptions, return values, and usage examples. Consider using a documentation format like LuaDoc or EmmyLua annotations.

    -- Anti-pattern: Manual testing or no testing
    function add(a, b)
      return a + b
    end
    
    -- Manual test
    print(add(2, 3) == 5 and "OK" or "FAIL")
    
    -- Better approach: Use a testing framework
    local luaunit = require("luaunit")
    
    function add(a, b)
      return a + b
    end
    
    function test_add()
      luaunit.assertEquals(add(2, 3), 5)
      luaunit.assertEquals(add(-1, 1), 0)
      luaunit.assertEquals(add(0, 0), 0)
    end
    
    luaunit.run("test_add")

    Write proper tests for your code using a testing framework like LuaUnit, Busted, or luatest. This makes it easier to verify that your code works as expected and to catch regressions.

    -- Anti-pattern: Inefficient algorithms
    function find_element(t, value)
      for i = 1, #t do
        if t[i] == value then
          return i
        end
      end
      return nil
    end
    
    -- Better approach: Use more efficient data structures
    function create_lookup_table(t)
      local lookup = {}
      for i, v in ipairs(t) do
        lookup[v] = i
      end
      return lookup
    end
    
    -- Usage
    local data = {10, 20, 30, 40, 50}
    local lookup = create_lookup_table(data)
    
    -- O(1) lookup instead of O(n)
    local index = lookup[30]  -- Returns 3

    Choose appropriate algorithms and data structures for your task. Consider time and space complexity, especially for operations that are performed frequently or with large data sets.

    -- Anti-pattern: Poor resource management
    function process_file(filename)
      local file = io.open(filename, "r")
      if not file then return nil end
      
      if some_condition() then
        return early_result  -- File is never closed!
      end
      
      -- Process file...
      file:close()
      return result
    end
    
    -- Better approach: Ensure resources are released
    function process_file(filename)
      local file, err = io.open(filename, "r")
      if not file then return nil, err end
      
      -- Use pcall to ensure file is closed even if an error occurs
      local success, result = pcall(function()
        if some_condition() then
          return early_result
        end
        
        -- Process file...
        return final_result
      end)
      
      file:close()  -- Always close the file
      
      if not success then
        return nil, result  -- result contains the error message
      end
      return result
    end

    Ensure that resources like files, network connections, and database connections are properly closed, even in error cases or early returns.

    -- Anti-pattern: Hardcoded configuration
    function connect_to_database()
      return db.connect("localhost", 5432, "mydb", "user", "password")
    end
    
    -- Better approach: Externalize configuration
    local config = require("config")
    
    function connect_to_database()
      return db.connect(
        config.db.host,
        config.db.port,
        config.db.name,
        config.db.user,
        config.db.password
      )
    end
    
    -- config.lua
    return {
      db = {
        host = os.getenv("DB_HOST") or "localhost",
        port = tonumber(os.getenv("DB_PORT")) or 5432,
        name = os.getenv("DB_NAME") or "mydb",
        user = os.getenv("DB_USER") or "user",
        password = os.getenv("DB_PASSWORD") or "password"
      }
    }

    Externalize configuration instead of hardcoding values. This makes your code more flexible and easier to deploy in different environments.

    HaskellJulia
    websitexgithublinkedin
    Powered by Mintlify
    Assistant
    Responses are generated using AI and may contain mistakes.