Fonctions à nombre variable d'arguments

I - Les arguments optionnels

Parfois, certaines fonctions que l'on utilise sont capables de faire beaucoup de choses, mais on n'a pas besoin de toujours tout utiliser. Prenons l'exemple d'une fonction d'affichage, comme la fonction print par exemple. Un cas d'usage fréquent de la fonction print est d'afficher une phrase ou un paragraphe, puis de retourner à la ligne. Mais parfois on voudrait ne pas retourner à la ligne à la fin d'un print. C'est pour cela que Neon possède la fonction output qui a le même comportement que la fonction print, mais qui ne retourne pas à la ligne à la fin. Grâce à cette fonction output et aux arguments optionnels, définissons une nouvelle fonction print qui se comporte comme la fonction print de base sauf quand on spécifie autre chose.

Mais d'abord, qu'est ce qu'un argument optionnel ?

Un argument optionnel est un argument de fonction que l'on peut ne pas renseigner lorsque l'on fait appel à la fonction. Dans le cas où un paramètre optionnel n'est pas renseigné, il prend alors une valeur par défaut.

Nous allons ajouter un argument optionnel à print. Cet argument sera la chaîne de caractères affichée tout à la fin de print. Dans le cas par défaut (lorsque l'on ne spécifie pas sa valeur), il sera égal à "\n" le caractère de retour à la ligne. Mais il sera aussi possible de spécifier sa valeur, et alors au lieu de retourner à la ligne, la nouvelle fonction print affichera la valeur du paramètre optionnel.

Voici à quoi ressemble la nouvelle fonction print :

function print(texte, fin := "\n") do

    output(texte + fin)

end

On peut utiliser cette fonction comme une fonction print normale, qui affichera du texte puis retournera à la ligne. Mais on peut également demander à la fonction de ne pas retourner à la ligne en mettant fin à la chaine de caractères vide "" :

print("coucou", fin := "")


De cette manière, vous pouvez définir autant de paramètres optionnels que vous voulez.

N'oubliez pas que les arguments optionnels sont également des arguments. Ca peut paraître bête dit comme ça, mais ça veut dire que l'on peut également parfaitement donner une valeur aux arguments optionnels sans spécifier son nom, mais juste en remplissant tous les arguments dans l'ordre. Ainsi, print("coucou", "") aura le même résultat que la ligne plus haut. Un argument optionnel est juste un argument normal, mais qui a un pouvoir en plus : celui pouvoir être oublié. On peut ainsi se demander à quoi l'écriture paramètre := valeur peut bien servir. Condsidérons une fonction f définie comme ceci :

function f(x, y, z := 0, t := Infinity) do

    return ((x + y)/t + z)

end

Cette fonction a deux arguments optionnels : z et t. Comment feriez-vous si vous vouliez donner une valeur à t, mais pas à z ? Vous n'avez pas d'autre choix que d'appeler la fonction de cette manière :

f(1, 2, t := 3)

En réalité, l'idée de donner des arguments en spécifiant son nom peut être étendue à tous types d'arguments afin de la rendre beaucoup plus puissante.


II - Être obligé de donner les arguments dans l'ordre ? C'est fini...

Quand les fonctions que l'on utilise prennent beaucoup d'arguments, il est difficile de se souvenir de l'ordre dans lequel donner tous les arguments. C'est pourquoi il pourrait être pratique de donner les arguments dans n'importe quel ordre et laisser l'interpréteur se débrouiller. C'est exactement ce que permet Neon. Reprenons la fonction f définie juste au dessus.

Il est parfaitement possible d'appeler cette fonction de la manière suivante :

f(t := 3, y := 2, x := 1, y := 4)

Dans ce cas, tous les paramètres auront bien la valeur spécifiée, peu importe leur ordre.

Mais on peut également combiner un appel normal et un appel avec des arguments spécifiés par nom. Par exemple, que ce passe-t-il si on appelle la fonction comme ceci ?

f(y := 2, 3, t := 1, 1)

Dans ce cas, tous les arguments dont le nom a été indiqué recevront bien leur valeur, et ensuite les autres arguments seront remplis dans l'ordre. Par exemple, ici, x aura la valeur 3 et z la valeur 1. Cependant, pour des soucis de clarté, il n'est pas recommandé de mélanger les méthodes d'affectation d'arguments.


III - Fonctions à nombre illimité d'arguments

Peut-être que vous l'avez remarqué, mais certaines fonction de base peuvent prendre un nombre illimité d'arguments. C'est le cas de la fonction print. Tous les arguments donnés à la fonction print seront affichés dans l'ordre. Eh bien bonne nouvelle, nous pouvons faire pareil dans notre fonction print de tout à l'heure. Définisons d'abord une fonction toute simple qui prend un nombre illimité d'arguments et qui les affiche un par un :

function print(...) do

    for (i, 0, len(__local_args__)) do

        output(__local_args__[i])

    end

end

Comme vous le voyez, pour définir une fonction à nombre illimité d'arguments, il suffit de mettre ... dans les arguments. Pour récupérer les arguments, il faut aller les chercher dans la liste __local_args__. Il est bien évidemment possible de faire des fonctions avec arguments obligatoires et optionnels en plus du nombre illimité d'arguments :

function f(x, y := 0, ...) do

return (x + y + len(__local_args__))

end

Dans ce cas, le comportement sera le même qu'expliqué tout à l'heure, mais en plus, tous les arguments supplémentaires (les arguments restants même après avoir rempli les arguments optionnels) seront stockés dans la liste __local_args__.

Mais si tous les arguments optionnels sont remplis avant de remplir __local_args__, peut-on définir des fonctions prenant un nombre illimité d'arguments, mais avec des arguments vraiment facultatifs ? Qui peuvent ne pas être spécifiés même en donnant un nombre illimité d'arguments ? Oui, et c'est le rôle des arguments vraiment optionnels. C'est vraiment leur nom.

Comment ça marche ? Rien de plus simple :

function print(..., fin := '\n') do

    for (i, 0, len(__local_args__)) do

        output(__local_args__[i])

    end

end

Comme vous le voyez j'ai défini la fonction que nous voulions tout à l'heure : une fonction print qui affiche un nombre illimité d'arguments, avec un paramètre optionnel pour spécifier la chaine de caractères de fin.

Contrairement aux arguments optionnels tout court qui pouvaient être donnés à la fonction sans spécifier le nom de l'argument, les arguments vraiment optionnels (ceux définis après ...) ne peuvent être donnés que via la syntaxe arg := val. D'ailleurs il est impossible de définir des fonctions prenant des arguments normaux après ... .


Pour résumer, voici une fonction :

function f(x, y := 0, z, ..., t := 0) do

    return (x + y + z + len(__local_args__) + t)

end

Comme vous le voyez, x et z sont des arguments obligatoires, tous les autres sont optionnels. Pour voir si vous avez tout compris essayez d'appelez f de toutes ces manières différentes :

⦁ En spécifiant uniquement x et z

⦁ En spécifiant x, z et y

⦁ En spécifiant x, z et t

⦁ En spécifiant x, z, y et plein d'autres arguments

En spécifiant x, z, y, t et plein d'autres arguments


Félicications, arrivé.e à ce stade-là, vous avez tout compris. Passons à un partie encore plus intéressante...