Back to Course HomeLesson 8 of 19
Intermediate to Advanced

Advanced Functions: Closures, Higher-Order Functions, and More

Lesson Overview

Now that you understand basic functions, it's time to explore advanced conceptsthat make Lua powerful and flexible. This lesson covers closures, higher-order functions, and functional programming patterns.

These concepts are essential for building modular, reusable, and elegant code.

Lesson Objectives

By the end of this lesson, you will be able to:

  • Understand and create closures
  • Use higher-order functions
  • Pass functions as arguments
  • Return functions from functions
  • Apply functional programming patterns

What Are Closures?

A closure is a function that remembers the variables from its outer scope, even after that scope has finished executing.

Think of it as a function that "captures" its environment.

LUA
function createCounter()
    local count = 0 -- captured variable
    return function()
        count = count + 1
        return count
    end
end

local counter = createCounter()
print(counter()) -- 1
print(counter()) -- 2
print(counter()) -- 3

The inner function remembers count even after createCounter has finished!

Why Closures Matter

Closures are used for:

  • Data Privacy - Hide internal state
  • State Management - Maintain state across calls
  • Factory Functions - Create customized functions
  • Callbacks - Pass context to event handlers

Higher-Order Functions

A higher-order function is a function that:

  • • Takes one or more functions as arguments, OR
  • • Returns a function as its result

Example: Function as Argument

LUA
function applyTwice(func, value)
    return func(func(value))
end

function double(x)
    return x * 2
end

print(applyTwice(double, 5)) -- Outputs: 20

Returning Functions

Functions can return other functions, creating powerful patterns.

LUA
function createMultiplier(factor)
    return function(x)
        return x * factor
    end
end

local triple = createMultiplier(3)
local quadruple = createMultiplier(4)

print(triple(10))    -- Outputs: 30
print(quadruple(10)) -- Outputs: 40

Practical Example: Map Function

Apply a function to every element in a table.

LUA
function map(tbl, func)
    local result = {}
    for i, v in ipairs(tbl) do
        result[i] = func(v)
    end
    return result
end

local numbers = {1, 2, 3, 4, 5}
local squared = map(numbers, function(x) return x * x end)

-- squared = {1, 4, 9, 16, 25}

Practical Example: Filter Function

Select elements that match a condition.

LUA
function filter(tbl, predicate)
    local result = {}
    for _, v in ipairs(tbl) do
        if predicate(v) then
            table.insert(result, v)
        end
    end
    return result
end

local numbers = {1, 2, 3, 4, 5, 6}
local evens = filter(numbers, function(x) return x % 2 == 0 end)

-- evens = {2, 4, 6}

Advanced Pattern: Memoization

Cache function results to avoid redundant calculations.

LUA
function memoize(func)
    local cache = {}
    return function(x)
        if cache[x] == nil then
            cache[x] = func(x)
        end
        return cache[x]
    end
end

local slowFibonacci = function(n)
    if n <= 1 then return n end
    return slowFibonacci(n-1) + slowFibonacci(n-2)
end

slowFibonacci = memoize(slowFibonacci)

Best Practices

  • Keep closures simple and focused
  • Document captured variables
  • Avoid creating closures in tight loops
  • Use closures for data privacy
  • Test closure behavior carefully

Summary

In this lesson, you learned:

  • Closures capture and remember their environment
  • Higher-order functions work with other functions
  • Functions can be passed as arguments and returned
  • Functional patterns like map, filter, and memoization
  • These concepts enable powerful, elegant code

Ready to test your knowledge?

Take the quiz to verify your understanding of advanced functions.