wiki:InsiaProgPerlFunc

Sommaire

Programmation Perl - Fonctions

1. Déclaration

Il y a plusieurs façons de déclarer et implémenter une fonction en Perl, mais en pratique une seule (la plus simple) est utilisée:

sub produit {
  my ($a, $b) = @_;

  return $a * b;
}

Nommage

Les conventions de nommage des fonctions est identique à celui des variables, sauf qu'il n'y pas besoin de symbole préfixe particulier. Comme les variables, la pratique standard consiste à utiliser des minuscules (y compris en orienté objet ou le CamelCase est rare comme nous le verrons).

Prototypage

Il est possible de déclarer un simple prototype de fonction, comme en C, mais cela est en général inutile. En effet, le compilateur de Perl utilise "2 passes": dans la première il collecte les symboles (fonctions et variables déclarés), dans la deuxième il les compile et effectue l'édition des liens. Il est donc tout à fait possible d'écrire ceci:

bonjour("world");

sub bonjour {
  my ($text) = @_;
  print "Hello $text !\n";
}

Appel

Quand il n'y a pas d'ambiguité dans la syntaxe de l'instruction, les parenthèses pour passer les arguments sont facultatives:

my @cles = sort keys %hash; # Ou: sort(keys(%hash));

La pratique consiste à utiliser les parenthèses à bon escient en favorisant la lisibilité:

  • Ne pas les utiliser quand on appel en cascade quelques fonctions simples, on obtient ainsi une forme quasiment "en anglais dans le texte" du programme (fonctions courantes: map, sort, grep, keys, ...)
  • Les utiliser quand divers opérateurs (arithmétiques et/ou de comparaisons) sont impliqués et les associativités et précédences sont délicates à définir

Il existe toutefois un piège: vous ne pouvez pas appeler une fonction sans utiliser les parenthèses si celle-ci est déclarée *après* l'utilisation (Perl n'ayant pas alors de moyen de devenir le type du symbole). En effet, les parenthèses désignent de manière définitive le symbole qui précède comme une fonction.

2. Les paramètres

On le voit dans la déclaration simplifiée de la fonction, les paramètres d'une fonction ne sont pas explicites: ils ne sont ni nommés ni typés. Cela peut permettre des fonctions très souples et capables de s'adapter facilement, comme écrire des programmes illisibles et incompréhensibles...

Les arguments passés à une fonction sont systématiquement convertis en une simple liste, appelée @_. En particulier:

  • ma_fonction(55): un seul argument scalaire devient donc une liste à un élément (@_ = (55)
  • ma_fonction(55, "hello"): les arguments sont naturellements considérés comme une liste (@_ = (55, "hello")
  • ma_fonction(55, @menu): les éléments de @menu sont concaténés au premier argument (@_ = (55, $menu[0], $menu[1], ...)
  • ma_fonction(%hash): le tableau associatif est "mis à plat", c'est-à-dire transformé en paires (clé, valeur) consécutives

Note: on peut éviter cette "mise à plat" des arguments d'une fonction en utilisant les références, que nous verrons plus tard.

Pour récupérer les paramètres en début de fonction, on utilise les fonctions de traitement de listes à notre disposition. Parmis les syntaxes les plus courantes, on trouve:

sub methode_a {
  my ($nb, $temps, $item) = @_;
  ...
}

sub methode_b {
  my $nb    = shift;  # Le paramètre par défaut de 'shift' est bien '@_'
  my $temps = shift;
  my $item  = shift;
  ...
}

Note: si votre fonction accepte plusieurs scalaires et une unique liste en arguments, passez la liste en dernier argument - l'utilisation sera alors triviale (ex: my ($facteur, @valeurs) = @_).

Référence et copie

Par défaut, les paramètres sont passés par référence. Cela signifie que les élements du tableau @_ sont équivalents aux arguments passés à la fonction. Exemple:

sub incremente {
  $_[0]++;
}

$a = 5;
incremente($a);
# $a vaut 6

Si on veut obtenir un passage par copie (cas le plus courant), il suffit d'effectuer explicitement cette copie en créant des variables locales (ce qui est décrit plus haut dans la récupération traditionnelle des paramètres):

sub n_incremente_pas {
  my $val = $_[0];  # Ou: my ($val) = @_;
  $val++;
}

$a = 5;
n_incremente_pas($a);
# $a vaut 5

Note: si une constante est passée à une fonction et que cette dernière tente de la modifier, une erreur aura lieu lors de l'exécution.

3. Valeur de retour

Le principe de la valeur de retour d'une fonction est identique à celui du passage des paramètres: il est généralisé avec le passage d'une liste. Une fonction peut donc retourner:

  • une liste vide: return ()
  • un scalaire (considéré comme une liste à 1 élément): return 42
  • une liste: return (5, 6, "bonjour")

Par défaut, une fonction Perl retourne la valeur de la dernière instruction évaluée, par exemple ici le résultat (booléen) du test:

sub est_pair {
  $_[0] % 2 == 0;
}

Il est bien entendu possible de rendre ce fait explicite, et surtout de pouvoir retourner une valeur depuis n'importe quel endroit de la fonction avec l'instruction return:

sub est_pair {
  return $_[0] % 2 == 0;
}

Note: pour les fonctions dont la valeur de retour n'a pas de signification particulière, il arrive souvent qu'on retour la valeur 1 (vrai en booléen), cette habitude venant de la programmation shell et du principe de "moindre surprise" quand on combine des fonctions dont attend un comportement "classique". Ex:

sub une_fonction {
  ...
  1;
}

Pour retourner une liste, il n'y a pas de surprise, et l'utilisation pour l'appelant peut être très pratique:

sub conjugue {
  my ($re, $im) = @_;
  return ($re, -$im);
}

my($cr, $ci) = conjugue($cr, $ci);

Contextualisation

Afin de pouvoir programmer des fonctions qui profitent de la sensibilité au contexte, comme décrit dans le chapitre sur les variables, on a à disposition une simple fonction:

sub meteo {
  ...
  return wantarray ? @temperatures_par_mois : $temperature_moyenne;
}

my @mensuel = meteo;
my $moyenne = meteo;

Cette possibilité est très souvent utilisée par les fonctions qui renvoient des listes, pour également renvoyer une information "utile" dans le cas du contexte scalaire. Exemple avec la date du jour en heure locale:

($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
$now = localtime();  # "Thu Oct 13 04:54:34 1994"

Note: il existe aussi le contexte vide, dans le cas où la fonction est appelée sans que sa valeur de retour soit utilisée (détectable par wantarray == undef).

Last modified 13 years ago Last modified on Jan 22, 2007, 12:45:36 AM