Fonctions

Définition

function nom(param1, param2) ... end
local function nom(param1, param2) ... end
local f = function(param1, param2) ... end

function table.champ(x) ... end          -- funcname avec '.'
function table:methode(x) ... end        -- funcname avec ':' (ajoute implicitement 'self')

function nom(...) ... end est un sucre syntaxique pour nom = function(...) ... end (et de même pour table.champ.sous.nom avec des . enchaînés). local function nom(...) ... end déclare la variable locale nom avant de compiler le corps, ce qui permet la récursivité directe.

Appel

f(1, 2)
f "chaine"          -- sucre : équivalent à f("chaine")
f { x = 1 }          -- sucre : équivalent à f({ x = 1 })
obj:methode(1, 2)    -- sucre : équivalent à obj.methode(obj, 1, 2)

Un appel dont l'unique argument est un littéral chaîne ou un constructeur de table peut omettre les parenthèses.

Méthodes et self

function t:m(a) ... end déclare une fonction dont le premier paramètre implicite s'appelle self (il n'apparaît pas dans la liste de paramètres écrite, mais existe dans le corps, comme un paramètre local ordinaire) :

local Compte = {}
function Compte:credit(montant)
    self.solde = self.solde + montant
end

obj:m(a) appelle la fonction trouvée à obj.m en lui passant obj comme premier argument (self). C'est une pure question de syntaxe d'appel : obj:m(a) et obj.m(obj, a) sont équivalents, que la fonction ait été déclarée avec : ou ..

self en dehors d'une déclaration : — une pseudo-variable dynamique

Contrairement à Lua standard, self n'est pas seulement le nom conventionnel du premier paramètre d'une fonction déclarée avec :. Toute référence à self qui n'est ni un paramètre déclaré, ni une variable locale, ni un upvalue capturé résout vers une valeur portée par la pile d'appel courante plutôt qu'un lookup global ordinaire — même dans une fonction déclarée avec . ou sans nom de table du tout :

function f(a, b)
    print(self, a, b)
end

local t = { f = f }

f(1, 2)          --> nil    1    2      (appel simple : pas de self)
t:f(1, 2)        --> table: ...  table: ...  1   (appel-méthode : self = t, ET a = t aussi,
                  --  par le sucre normal du ':' — deux mécanismes distincts qui coïncident ici)

Cette valeur de self par frame d'appel se résout dans cet ordre :

  1. Si la fonction est appelée avec : (obj:f(...)), self de cette frame vaut obj — que f ait ou non été déclarée avec :.
  2. Sinon, self est hérité de la fermeture englobante : une fonction imbriquée dans le corps d'une méthode (même définie avec function, sans :) voit le self de la méthode qui l'englobe, capturé au moment de la fermeture — pratique pour une fonction utilitaire locale à une méthode sans avoir à la redéclarer avec : ni à passer self explicitement.
  3. Sinon self vaut nil (aucun appel-méthode dans la chaîne d'appel/fermetures).
local Compte = {}
function Compte:relever()
    local function afficher()      -- pas déclarée avec ':' ...
        print(self.solde)          -- ... mais voit quand même le 'self' de relever()
    end
    afficher()
end

Dès que self est un paramètre déclaré (fonction définie avec :) ou une variable locale du même nom, c'est cette liaison lexicale ordinaire qui s'applique — le mécanisme dynamique ci-dessus ne sert que de repli quand aucune n'existe. Voir Différences avec Lua pour ce que ça change par rapport à Lua standard.

Paramètres et arguments

local function f(a, b) ... end
f(1)          -- b vaut nil
f(1, 2, 3)    -- le 3ᵉ argument est ignoré

Le nombre d'arguments passés n'a pas à correspondre au nombre de paramètres déclarés : les paramètres manquants valent nil, les arguments excédentaires sont ignorés (sauf s'ils sont récupérés via ..., voir plus bas).

Fonctions variadiques

local function f(a, ...)
    print(a, ...)
    local args = { ... }
    local n = select("#", ...)   -- select() vient de la bibliothèque standard
end

... en dernière position de la liste de paramètres capture tous les arguments restants. Voir Variables pour son usage comme expression.

Valeurs de retour multiples

local function minmax(t)
    return t[1], t[#t]
end

local lo, hi = minmax({ 3, 1, 4, 1, 5 })

Une fonction peut retourner zéro, une ou plusieurs valeurs (return e1, e2, ...). Voir Variables pour les règles d'adaptation du nombre de valeurs selon le contexte (affectation, argument, élément de table...).

Fermetures (upvalues)

Une fonction définie à l'intérieur d'une autre capture les variables locales de la fonction englobante qu'elle référence (« upvalues ») — la fermeture reste valide même après le retour de la fonction englobante, et référence la même variable qu'elle (pas une copie figée) :

local function makeCounter()
    local n = 0
    return function()
        n = n + 1
        return n
    end
end

local next = makeCounter()
print(next(), next(), next())   --> 1  2  3

Chaque appel de makeCounter() crée une nouvelle variable n et donc une fermeture indépendante.

Fonctions anonymes

table.sort(t, function(a, b) return a > b end)

Une expression function(...) ... end (sans nom) est utilisable partout où une expression est attendue — argument, valeur de table, etc.