Menu
Coddy logo textTech

Tablas de solo lectura

Parte de la sección Object Oriented Programming del Journey de Lua de Coddy — lección 46 de 70.

Los closures proporcionan una verdadera privacidad, pero requieren definir métodos dentro del constructor. Existe otro enfoque para un caso de uso diferente: hacer que un objeto sea de solo lectura después de su creación. Esto es útil cuando se desea que los campos sean visibles pero inalterables, como las coordenadas de un punto fijo.

El metamétodo __newindex intercepta los intentos de asignar nuevos valores a una tabla. Al hacer que bloquee todas las asignaciones, puedes congelar un objeto:

local ImmutablePoint = {}

function ImmutablePoint.new(x, y)
    local data = {x = x, y = y}
    
    local proxy = {}
    setmetatable(proxy, {
        __index = data,
        __newindex = function()
            error("Cannot modify immutable object")
        end
    })
    
    return proxy
end

El truco consiste en utilizar una tabla proxy. Los datos reales residen en data, mientras que el usuario interactúa con el proxy vacío.

Al leer, __index obtiene de data. Al escribir, __newindex se activa en su lugar—y lo bloqueamos:

local p = ImmutablePoint.new(10, 20)
print(p.x)  -- 10 (la lectura funciona)
p.x = 50    -- Error: No se puede modificar un objeto inmutable

Este patrón es valioso para objetos de configuración, constantes matemáticas o cualquier dato que nunca deba cambiar después de la inicialización. El objeto sigue siendo totalmente legible; simplemente no puedes alterarlo.

challenge icon

Desafío

Fácil

¡Vamos a construir una clase ImmutableConfig que cree objetos de configuración de solo lectura! Una vez creados, estos objetos de configuración deben permitir la lectura de sus ajustes pero bloquear completamente cualquier intento de modificarlos.

Organizarás tu código en dos archivos:

  • ImmutableConfig.lua: Crea un módulo que produzca objetos de configuración congelados. Tu función .new(appName, version, maxUsers) debe almacenar estos tres valores internamente y luego devolver una tabla proxy que permita leer todos los campos pero impida cualquier modificación. Cuando alguien intente cambiar un valor, debe imprimir Error: Config is read-only en lugar de lanzar un error real.
  • main.lua: ¡Dale vida a tu ImmutableConfig! Lee tres entradas para los valores de configuración, crea un objeto de configuración y luego demuestra que funciona correctamente:
    • Imprimiendo los tres valores originales
    • Intentando modificar el campo maxUsers (lo que debería activar el mensaje de error)
    • Imprimiendo maxUsers de nuevo para demostrar que no se cambió realmente

Recibirás tres entradas:

  1. El nombre de la aplicación (una cadena)
  2. La versión (una cadena)
  3. El número máximo de usuarios (un número)

Tu salida debe mostrar los valores de configuración, el error cuando se intenta la modificación y la confirmación de que el valor permaneció sin cambios:

App: {appName}
Version: {version}
Max Users: {maxUsers}
Error: Config is read-only
Max Users: {maxUsers}

Por ejemplo, si las entradas son MyApp, 2.0, y 100, la salida debe ser:

App: MyApp
Version: 2.0
Max Users: 100
Error: Config is read-only
Max Users: 100

Recuerda: el patrón proxy utiliza una tabla vacía con la que el usuario interactúa, mientras que los datos reales residen en una tabla interna separada. ¡El metamétodo __index recupera los datos de la tabla interna, y __newindex intercepta (y bloquea) cualquier intento de escritura!

Hoja de referencia

El metamétodo __newindex intercepta los intentos de asignar nuevos valores a una tabla. Al bloquear todas las asignaciones, puedes crear objetos inmutables (de solo lectura):

local ImmutablePoint = {}

function ImmutablePoint.new(x, y)
    local data = {x = x, y = y}
    
    local proxy = {}
    setmetatable(proxy, {
        __index = data,
        __newindex = function()
            error("Cannot modify immutable object")
        end
    })
    
    return proxy
end

El patrón de proxy utiliza una tabla vacía (proxy) con la que el usuario interactúa, mientras que los datos reales residen en una tabla interna separada (data):

  • __index recupera valores de la tabla data al realizar una lectura
  • __newindex intercepta los intentos de escritura y los bloquea
local p = ImmutablePoint.new(10, 20)
print(p.x)  -- 10 (la lectura funciona)
p.x = 50    -- Error: Cannot modify immutable object

Este patrón es útil para objetos de configuración, constantes matemáticas o cualquier dato que deba permanecer sin cambios después de su inicialización.

Pruébalo tú mismo

-- Importar el módulo ImmutableConfig
local ImmutableConfig = require('ImmutableConfig')

-- Leer entradas
local appName = io.read()
local version = io.read()
local maxUsers = tonumber(io.read())

-- TODO: Crear un objeto de configuración usando ImmutableConfig.new()

-- TODO: Imprimir los tres valores originales en el formato:
-- App: {appName}
-- Version: {version}
-- Max Users: {maxUsers}

-- TODO: Intentar modificar el campo maxUsers (esto debería activar un mensaje de error)

-- TODO: Imprimir maxUsers de nuevo para demostrar que no fue cambiado
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Object Oriented Programming