Menu
Coddy logo textTech

Tables en lecture seule

Fait partie de la section Programmation orientée objet du Journey Lua de Coddy. Leçon 46 sur 70.

Les fermetures assurent une véritable confidentialité, mais elles nécessitent de définir les méthodes à l’intérieur du constructeur. Il existe une autre approche pour un cas d’utilisation différent : rendre un objet en lecture seule après sa création. Cela est utile lorsque vous souhaitez que les champs soient visibles mais impossibles à modifier, comme les coordonnées d’un point fixe.

La métaméthode __newindex intercepte les tentatives d’affectation de nouvelles valeurs à une table. En la faisant bloquer toutes les affectations, vous pouvez geler un objet :

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

L’astuce consiste à utiliser une table proxy. Les données réelles se trouvent dans data, tandis que l’utilisateur interagit avec la proxy vide.

Lors de la lecture, __index récupère les données depuis data. Lors de l’écriture, __newindex se déclenche à la place, et nous le bloquons :

local p = ImmutablePoint.new(10, 20)
print(p.x)  -- 10 (la lecture fonctionne)
p.x = 50    -- Erreur : Impossible de modifier un objet immuable

Ce modèle est utile pour les objets de configuration, les constantes mathématiques ou toute donnée qui ne doit jamais changer après son initialisation. L’objet reste entièrement lisible. Vous ne pouvez simplement pas le modifier.

challenge icon

Défi

Facile

Construisons une classe ImmutableConfig qui crée des objets de configuration en lecture seule ! Une fois créés, ces objets de configuration doivent permettre de lire leurs paramètres, tout en bloquant complètement toute tentative de modification.

Vous organiserez votre code sur deux fichiers :

  • ImmutableConfig.lua : créez un module qui produit des objets de configuration gelés. Votre fonction .new(appName, version, maxUsers) doit stocker ces trois valeurs en interne, puis renvoyer une table proxy qui permet de lire tous les champs, mais empêche toute modification. Lorsque quelqu'un essaie de modifier une valeur, le programme doit afficher Error: Config is read-only au lieu de lever une véritable erreur.
  • main.lua : donnez vie à votre ImmutableConfig ! Lisez trois entrées pour les valeurs de configuration, créez un objet de configuration, puis démontrez qu'il fonctionne correctement en :
    • affichant les trois valeurs d'origine ;
    • tentant de modifier le champ maxUsers (ce qui doit déclencher le message d'erreur) ;
    • affichant à nouveau maxUsers pour prouver qu'il n'a pas réellement été modifié.

Vous recevrez trois entrées :

  1. Le nom de l'application (une chaîne de caractères)
  2. La version (une chaîne de caractères)
  3. Le nombre maximal d'utilisateurs (un nombre)

Votre sortie doit afficher les valeurs de configuration, l'erreur lors de la tentative de modification et la confirmation que la valeur est restée inchangée :

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

Par exemple, si les entrées sont MyApp, 2.0 et 100, la sortie doit être :

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

Souvenez-vous : le modèle du proxy utilise une table vide avec laquelle l'utilisateur interagit, tandis que les données réelles résident dans une table interne distincte. La métaméthode __index récupère les données depuis la table de données, et __newindex intercepte (et bloque) toute tentative d'écriture !

Essayez vous-même

-- Importer le module ImmutableConfig
local ImmutableConfig = require('ImmutableConfig')

-- Lire les entrées
local appName = io.read()
local version = io.read()
local maxUsers = tonumber(io.read())

-- TODO: Créer un objet config en utilisant ImmutableConfig.new()

-- TODO: Afficher les trois valeurs d'origine au format :
-- App: {appName}
-- Version: {version}
-- Max Users: {maxUsers}

-- TODO: Tenter de modifier le champ maxUsers (cela devrait déclencher un message d'erreur)

-- TODO: Afficher maxUsers à nouveau pour prouver qu'il n'a pas été modifié
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation orientée objet

Entraînez-vous par vous-même : Compilateur Lua en ligne