Table des matières

Perl Philosophy ou Le PERL est "l'avenir de l'homme" par Danjer

Introduction

En général la documentation du perl est bien faite et accessible à tous. Le but de ce document est de faire profiter les autres de mes erreurs dans l’utilisation de ce langage et de leur faire gagner du temps.

Il ne faut pas voir ce langage comme une exécution lourde et une cause perdue pour la maintenabilité. Dans 90% des cas l’emploi et/ou le choix du Perl sera fait pour des questions d’efficacité. Quand j’emploie efficacité, j’entends par ce terme : du temps en plus pour vous. Si l’on prend l’exemple d’une action ‘one shot’ qui comprend un grand nombre de tâches répétitives. Ne pas automatiser/scripter cette tâche est une hérésie.

En partant de rien, faire cette action peut prendre (on va dire) une demi-journée de code pour une seule et unique exécution de 5 minutes. Soyons fou imaginons la réalisation de cette action en shell :

  • temps d’écriture du script,
  • temps de lecture de mans1),
  • temps de bricolages et de tests,
  • Le tout en trois bonnes heures pour un temps d’exécution de 25 minutes.

Maintenant voyons la chose en Perl :

  • 1 heure d’écriture et de tests,
  • pour 30 minutes d’exécution.

Si l’on part du principe qu’une demi-journée c’est 3h30 :

  • Le mec qui le fait en C n’a parlé à personne pendant cette période et a sauté le déjeuner pour optimiser son programme pour faire descendre le temps d’exécution en dessous de la barre des 2 minutes.
  • Le mec qui le fait en shell a râlé toute la matinée sur les versions des programmes shell qui sont sur la machine de prod et casse les couilles à tout le monde en chantant les exploits de son FreeBSD qui chez lui aurait mis 10 minutes pour s’exécuter avec son Bi-proc.
  • Et il y a le mec en Perl qui a bien pris son temps pour accoucher de son script puis a passé une bonne demi-heure au téléphone avec ses potes ainsi qu’une heure à fumer des clopes, boire des cafés et expliquer à la bombe de l’accueil pourquoi il faut qu’elle largue son mec.

Donc le Perl, vous apportera une vie sexuelle et un cancer des poumons... ou de la gorge.

Débat

Pourquoi le Perl c'est tout naze ?

  • C’est un langage de script, donc ce n’est pas un langage élite.
  • C’est un peu lent, en début d’exécution, à cause des modules que l’on utilise.
  • C’est un langage trop permissif, on peut faire le contraire de ce que l’on veut sans comprendre pourquoi.
  • C’est un langage trop verbeux.
  • C’est rarement portable d’une archi à une autre.
  • C’est obligatoire de lire la doc et c’est écrit en anglais.

Pourquoi le Perl c'est vraiment trop de la balle ?

  • C’est un langage de script cela rend les choses plus simple.
  • C’est un langage verbeux qui permet de faire des jeux de mots.
  • C’est permissif, c’est donc rapide d’écrire un petit truc sans se prendre la tête avec plein de trucs inutiles.
  • La Doc est vraiment ultime.
  • La Documentation est disponible en français, si l’on fait l’acquisition des livres O’Reilly

Philosophie

Je vais essayer de dévoiler tout au long de ce document l’esprit du langage. Et prouver que ce langage a les propriétés suivantes :

  • La conception du langage s’appuie sur la forme de la pensée humaine et ne force pas les gens à rentrer dans un moule.
  • N’oblige pas un style particulier de programmation aux programmeurs.
  • Tout faire pour que le Perl devienne le langage qui domine le monde. Tout faire pour que l’interpréteur soit disponible. C’est gratuit et téléchargeable sur le net.
  • C’est un moyen d’expression qui laisse de la place pour l’impertinence, l’humour, le plaisir et les mauvais jeux de mots.
  • Permet aux programmeurs de devenir des artistes.

Le PERL est plein de subtilités

Ce qui est vraiment très intéressant avec ce langage, c’est que l’on a l’impression qu’il progresse au fur à mesure que l’on progresse dans son utilisation. Chaque niveau de maîtrise du PERL a sa pratique, ses possibilités et ses limites.

Le PERL est la fusion de différents mondes de la programmation :

  • Les langages compilés : C, C++, etc...
  • Les langages interprétés : Shell (sh, ksh), etc...

On retrouve très souvent les influences d’autres langages dans le PERL.

Juste une petite note pour les fans de PHP

Le PHP a été inventé, en 1994, par le Canadien Rasmus Lerdorf, en modifiant un peu apache et en intégrant la version 5.0 de PERL. Rasmus avait mis en place ce système pour savoir qui consultait son CV sur le net2). Il baptisa son bébé : Personal Home PagePHP. Ce qui posa beaucoup de problèmes pour développer le langage et l’imposer3). En 1997, pour faire plus cool et en pompant un peu GNU, le nom est changé pour PHP: HyperText Processor (Définition récursive). Bref la grande question n’est pas de savoir : “Quel est le langage le meilleur entre le PERL et le PHP ?”. Car finalement le PHP dérive du PERL. D’autre part, au-delà des questions stupides : “Quel est le langage le plus cool ?”, il faut plutôt se demander : “Lequel est le plus abouti ?”

Langage Version 1.0 support Objets support vraiment Objets
PHP 1994 2000 2005
Perl 1987 1994 1997

Je pense que l’on pourra vraiment parler de langage de programmation pour le PHP à partir de la version 5 voir 6. Le PERL a quelques années d’avance qui vont petit à petit se réduire.

Voir Perl PHP Soap - Comment combiner la puissance de deux languages ?

Note pour les critiques

En me relisant, je me disais qu’un bon nombre de notions sont interdépendantes. Il serait possible de changer la présentation mais je pense qu’il est plus abordable de commencer par les premières questions que l’on se pose quand on est face à un nouveau langage :

  • C’est quoi la doc ? Ouelleest ?
  • Quels sont les structures de données ? Comment je les manipule ?
  • Comment exprimer un algorithme ? Quels sont les structures de contrôles ?
  • Comment faire des choses plus compliquées ?
  • etc...

Comment chercher l'information ?

Chercher l’information est primordial avec ce langage. D’autre part je ne pense pas que cela soit utile de réécrire une nième doc sur le Perl. Des bien plus intelligents et surtout meilleurs en orthographe que moi l’on fait auparavant.

Une petite note : les bouquins O’Reilly de Perl ne sont que la documentation fournie avec PERL en format papier.

Man perl

Dans le man de perl on va trouver deux choses intéressantes :

  1. Comment utiliser l’interpréteur,
  2. La description des autres mans associés à perl.

Voici un bout du man :

  • perl An overview of perl (this section)
  • perltoc Perl documentation table of contents
  • perldata Perl data structures
  • perlsyn Perl syntax
  • perlop Perl operators and precedence
  • perlre Perl regular expressions
  • perlrun Perl execution and options
  • etc...

La lecture des différents mans est très enrichissante.

perlsyn

On peut considérer que si on lit le man perlsyn on sait faire du perl. L’essentiel est dans ce man. C’est la première lecture pour un débutant et la référence pour un confirmé. Il faut être réaliste : on ne comprend pas tout à la première lecture. A chaque fois qu’on le relit, on y voit quelque chose de nouveau ou une manière de procéder que l’on n’était pas capable d’envisager avant.

perlop

C’est la bible des opérateurs, le Perl est riche en mots-clés et en opérateurs. C’est vraiment pratique de pouvoir choisir son opérateur en fonction de ce que l’on est en train de faire, de sa propre norme, de son humeur ou du trip en cours. Par exemple on peut écrire les lignes suivantes qui donneront toutes la même chose :

$failed && exit;
$failed and exit;
! $failed || exit;
not $failed or exit;
! $failed or exit;
not $failed || exit;

C’est le grand jeu des PerlMongers4) : l’art d’écrire la même signification logique de manière différente. Ce qui est un plus dans le langage : on peut s’exprimer en PERL avec son propre style.

perlfunc

Il contient toutes les fonctions internes au langage comme split, join, etc... Le problème c’est qu’elles sont toutes les unes avec les autres dans le man. C’est pratique, cela permet de découvrir de nouvelles fonctions, même si l’on a un peu l’impression de lire un dictionnaire.

Les modules

Un grand nombre de modules sont disponibles sur l’internet. Chaque module publié se doit d’avoir une documentation incluse dans le module. Lors de la lecture d’un script on peut tomber sur une ligne qui ressemble à cela :

use File::Find;

Ceci en gros pour dire qu’un module est utilisé avec le script. La plupart du temps les noms de modules sont explicites, mais pour plus d’information on peut avoir plus d’info avec la commande suivante :

perlkiller@mybox$ man File::Find

perldoc

Perldoc est une commande qui permet à la base d’avoir accès à la doc de perl sur les machines qui ne disposent pas de man. A partir du moment où PERL est disponible, cette commande doit l’être aussi.

On retrouve les mêmes fonctionnalités que pour le man :

perlkiller@mybox$ perldoc perlsyn

perldoc Truc::Module

C’est presque la même chose que pour la version du man à une grosse différence près : la version man du module est générée à l’installation (s’il y a un système d’installation). Pour sa part, perldoc va directement lire la documentation contenue dans le module.

perlkiller@mybox$ perldoc File::Find

perldoc -f func

Ceci est très pratique comparé à la version man. Si l’on veut avoir accès à la définition d’une fonction directement.

perldoc -q

Dans les mans de perl il existe des FAQ inclus (perlfaq[1-9] ce qui a permis d’écrire les Cook book). Il peut être très lourd de chercher quelque chose dans ces 9 mans différents, mais heureusement, perldoc est là pour ça. Par exemple, si vous voulez savoir comment faire l’équivalent de la commande find mais en perl :

perlkiller@mybox$ perldoc -q find

On obtiendra alors une compilation des questions où le mot clef find est présent.

Restons critique

La documentation de Perl est ce qui fait sa force et sa faiblesse. On n’a pas besoin d’aller rechercher la documentation sur le net comme cela est le cas pour PHP, elle est (la plupart du temps) disponible sur la machine, elle même. D’autre part chaque module contient sa documentation cela en ralenti d’autant plus le chargement/l’interprétation du script qui l’utiliserait.

Bases Practices pour les débutants

Comment s'y retrouver ?

Le Perl est un langage plein de contradictions, c’est à la fois simple et difficile. Lorsque l’on s’exprime en Perl, il existe une certaine permissivité dans l’expression d’un algorithme et la possibilité de faire des sous-entendus. Cela entraîne inévitablement des contresens. Voici ce que cette section va vous apporter :

  • Éviter les pièges de débutants,
  • Pouvoir rendre son code compréhensible par les autres,
  • Faciliter le travail de l’optimiseur.

Warnings

Il est possible de rendre l’interpréteur de perl plus restrictif au niveau de la syntaxe du langage grâce au module warning. Tout petit script devrait comporter au moins cette vérification.

Voici un petit script. Celui-ci ne fait qu’afficher la chaîne ‘“Hello”‘, il comporte aussi un test de comparaison sur une chaîne de caractères.

#!/usr/bin/perl
 
$check = "do hello";
if ($check == 'do hello') {
  $var = "Hello";
  print $var, "\n";
}

En soit, le code fonctionne et reste compréhensible :

bash-2.05b$ ~/perl/test_warn.pl 
Hello

Reprenons-le en détail :

1:#!/usr/bin/perl
2:
3:$check = "do hello";
4:if ($check == 'do hello') {
5:  $var = "Hello";
6:  print $var, "\n";
7:}
  1. La ligne de l’interpréteur (Note: on pourrait rajoute des arguments),
  2. Une ligne d’aération,
  3. Initialisation de la variable ‘$check’ avec la chaîne ‘“do hello”‘,
  4. Début de structure conditionnelle et test de comparaison numérique avec une chaîne,
  5. Initialisation de la variable ‘$var’ avec la chaîne ‘“Hello”‘,
  6. Affichage de la variable ‘$var’ suivit d’une nouvelle ligne,
  7. Fin de la structure conditionnelle

Maintenant nous allons augmenter le niveau de warnings. Pour ce faire il existe deux méthodes :

  • Par argument optionnel de l’interpréteur :
#!/usr/bin/perl -w
  • Par package/module :
#!/usr/bin/perl
 
use warning;

L’utilisation du module permet d’influer sur les pragmas des warnings.

Revenons à notre petit script :

#!/usr/bin/perl -w
 
$check = "do hello";
if ($check == 'do hello') {
  $var = "Hello";
  print $var, "\n";
}

Examinons l’exécution de celui-ci :

bash-2.05b$ ./test_warn.pl
Argument "do hello" isn't numeric in numeric eq (==) at ./test_warn.pl line 4.
Argument "do hello" isn't numeric in numeric eq (==) at ./test_warn.pl line 4.
Hello

La on peut observer que l’interpréteur Perl s’indigne de l’utilisation d’un opérateur ‘numérique’ dans un contexte ou un opérateur de ‘chaîne’ devrait être présent. Il faut toujours garder à l’esprit que le PERL est un langage assez verbeux qui permet de vous exprimer en argot et en littéraire. Sans utiliser les warnings, il est facile de se mélanger les pinceaux et de faire le contraire de ce que l’on voulait faire.

La grande question pour les experts : Pourquoi ce petit bout de code écrit deux fois le warnings ?

Voici l’opérateur qu’il aurait été de bon aloi d’utiliser :

#!/usr/bin/perl -w
 
$check = "do hello";
if ($check eq 'do hello') {
  $var = "Hello";
  print $var, "\n";
}

Diagnostics

Beaucoup diront : “C’est bien gentil les warnings, c’est trop dur de les enlever !!!“. Ce genre de comportement stupide entraîne invariablement des exécutions foireuses. J’avoue qu’il n’est pas forcement aisé de trouver une solution pour éliminer un warning. Pour cela il existe un package pour éduquer le programmeur, c’est diagnostics.

Réutilisons notre petit script :

#!/usr/bin/perl -w
 
use diagnostics;
$check = "do hello";
if ($check == 'do hello') {
  $var = "Hello";
  print $var, "\n";
}

Exécutons-le :

bash-2.05b$ ./test_warn.pl
Argument "do hello" isn't numeric in numeric eq (==) at ./test_warn.pl line 7 (#1)
    (W numeric) The indicated string was fed as an argument to an operator
    that expected a numeric value instead.  If you're fortunate the message
    will identify which operator was so unfortunate.
    
Hello

Pour chaque warnings vous aurez le droit à une explication plus complète pour pouvoir résoudre le problème.

La grande question pour les experts : Pourquoi ce petit bout de code affiche maintenant qu’une fois le warnings ?

Note : L’utilisation de diagnotics entraîne l’utilisation du package warning. Une fois le script développé et testé il faudrait retirer l’utilisation de celui-ci. A chaque exécution le fichier ‘diagnostics.pm’ est lu et chargé, ce qui ralentie le démarrage de l’exécution du script.

Strict

Les warnings permettent d’avoir un retour sur les erreurs syntaxiques potentielles et ne vérifient en aucun cas que vous savez ce que vous faites en manipulant des données. Le perl est aussi laxiste sur manipulation des structures de données que sur la syntaxe. C’est pourquoi il est possible de restreindre Perl pour stopper le programme (Parfois à l’interprétation) au moindre problème de cohérence de construction.

Pour donner un exemple, en perl il est possible d’utiliser/créer une variable sans la déclarer. L’utilisation de ‘strict’ interdit ce genre de pratique.

Reprenons encore notre petit script :

#!/usr/bin/perl -w
 
use strict;
$check = "do hello";
if ($check eq 'do hello') {
  $var = "Hello";
  print $var, "\n";
}
bash-2.05b$ ./test_warn.pl
Global symbol "$check" requires explicit package name at ./test_warn.pl line 7.
Global symbol "$check" requires explicit package name at ./test_warn.pl line 8.
Global symbol "$var" requires explicit package name at ./test_warn.pl line 9.
Global symbol "$var" requires explicit package name at ./test_warn.pl line 10.
Execution of ./test_warn.pl aborted due to compilation errors.

Visiblement le script refuse de s’exécuter comme précédemment. Rajoutons ‘diagnostics’ pour comprendre ces messages barbares.

#!/usr/bin/perl -w
 
use strict;
use diagnostics;
 
$check = "do hello";
if ($check eq 'do hello') {
  $var = "Hello";
  print $var, "\n";
}
bash-2.05b$ ./test_warn.pl
Global symbol "$check" requires explicit package name at ./test_warn.pl line 7.
Global symbol "$check" requires explicit package name at ./test_warn.pl line 8.
Global symbol "$var" requires explicit package name at ./test_warn.pl line 9.
Global symbol "$var" requires explicit package name at ./test_warn.pl line 10.
Execution of ./test_warn.pl aborted due to compilation errors (#1)
    (F) You've said "use strict vars", which indicates that all variables
    must either be lexically scoped (using "my"), declared beforehand using
    "our", or explicitly qualified to say which package the global variable
    is in (using "::").
    
Uncaught exception from user code:
        Global symbol "$check" requires explicit package name at ./test_warn.pl line 7.
Global symbol "$check" requires explicit package name at ./test_warn.pl line 8.
Global symbol "$var" requires explicit package name at ./test_warn.pl line 9.
Global symbol "$var" requires explicit package name at ./test_warn.pl line 10.
Execution of ./test_warn.pl aborted due to compilation errors.

Après analyse des indications de diagnostics donc lecture d’une vraie phrase en anglais. On peut commencer à comprendre le problème. L’utilisation de ‘strict’ oblige (entre autres) utiliser des variables a porte lexicale. Nous reviendrons plus tard sur le sujet, pour simplifier on va dire qu’il faut ‘déclarer’ les variables avec le mot clef “my“.

#!/usr/bin/perl -w
 
use strict;
use diagnostics;
 
my $check = "do hello";
if ($check eq 'do hello') {
  my $var = "Hello";
  print $var, "\n";
}
bash-2.05b$ ./test_warn.pl
Hello

L’ajout du mot clef “my” aux bons endroits a permit de supprimer tous les messages d’erreurs. Car pour chaque utilisation d’une variable nous avions le droit a une erreur.

Conclusion

On peut faire perdre a Perl toute sa souplesse ce qui permet d’ajouter de la rigueur. La contre partie est du passer du temps (au moins au début) à maîtriser les subtilités de la syntaxe et des constructions.

Les Structures de données

Quelles sont les moyens de manipuler des données les plus efficaces ? C’est une question à laquelle nous essaieront de répondre dans cette partie.

Les types de variables

Le Perl est un langage faiblement type. Ce qui signifie, par opposition à un autre langage fortement typé comme C, qu’il n’est pas nécessaire de déclarer le type donnée avant de pouvoir l’utiliser. Dans un langage fortement typé cette opération est indispensable pour déterminer l’espace mémoire avant utilisation. A l’inverse dans un langage faiblement typé l’espace mémoire nécessaire est déterminé en cours d’utilisation. Ce type mécanisme est appelé variables scalaires car elles changent de taille dynamiquement.

En Perl il existe trois principaux types de variables :

  • Les variables scalaires,
  • Les tableaux,
  • Les tables de Hash (Tableaux associatifs en français).

L’objectif de cette section est plutôt de montrer des utilisations pratiques des variables.

Les variables scalaires

Un des objectifs de la programmation est de s’abstraire des problèmes d’allocation/de gestion de la mémoire pour se concentrer sur les données elles-mêmes, leurs contenus, leurs sens.

Affectation

Note: Les exemples seront écrit sans interpréteurs ou inclusion de package pour des questions de lisibilité.

my $var;
$var = "coucou\n";
$var = 'coucou\n';
$var = 4;

Dans cet exemple on remarque que l’on peut affecter une chaîne ou un numérique à une variable de la même manière. De ce fait une variable peut contenir :

  • Une chaîne de caractères,
  • Une valeur numérique,
  • Rien du tout.

En PERL, on peut explicitement écrire qu’une variable ne contient rien du tout :

$var = undef;

Elle contient donc une valeur indéfinie.

Ce principe à pour impact de pouvoir savoir si une variable est définie ou pas.

Quotes

Il y a une différence entre les simples quotes5) et les doubles quotes. Les simples quotes ne sont pas interprétées, dans le cas de l’utilisation d’un caractère de contrôle, dans la chaîne, comme ‘\n’ il est considéré comme deux caractères : ‘\’ et un ‘n’. Voici le tableau des Quote and Quote-like Operators du ‘man perlop‘, a méditer.

           Customary  Generic        Meaning        Interpolates
               ''       q{}          Literal             no
               ""      qq{}          Literal             yes
               ``      qx{}          Command             yes*
                       qw{}         Word list            no
               //       m{}       Pattern match          yes*
                       qr{}          Pattern             yes*
                        s{}{}      Substitution          yes*
                       tr{}{}    Transliteration         no (but see below)
               <<EOF                 here-doc            yes*

               * unless the delimiter is ''.

Dans la plupart des cas il est préférable d’utiliser les doubles quotes pour éviter les erreurs d’interprétations. Il ne faut pas oublier les différentes possibilités, un jour elles vous seront utiles.

Les tableaux

Les tableaux et les listes chaînées sont souvent dissociés, en Perl ce n’est pas le cas. Un tableau peut être considéré comme un tableau, une liste chaînée, ou une pile, en fonction des besoins ou du contexte.

Afficher un tableau

Un des problèmes récurent pour le débutant est d’utiliser correctement un tableau. L’habitude d’autre langage le pousse utiliser les tableaux de la manière suivante :

my @tab;
 
$tab[0] = "coucou";
$tab[1] = "blah";
$tab[2] = "blah";
$tab[3] = "cool";
 
my $i;
 
for ($i = 0; $i <= $#tab; $i++) {
  print $tab[$i], ",";
}
print "\n";
 
 
foreach my $elm (@tab) {
  print $elm, ",";
}
print "\n";
bash-2.05b$ ./test_tab.pl
coucou,blah,blah,cool,
coucou,blah,blah,cool,

Dans ce code montre deux types de boucle pour afficher le tableau :

  • Avec un boucle ‘for’ on considère le tableau comme un tableau et l’on y accède par le biais d’un indice. Cette méthode est peu utilisée pour ce genre de pratique en Perl, car c’est la plus lente. Il est rare que l’accès par indice soit utilisé pour parcourir l’ensemble du tableau, par contre c’est la plus rapide pour accéder à un élément du tableau.
  • Avec un boucle ‘foreach’ on considère le tableau comme une liste chaînée. C’est la plus rapide pour parcourir tous les éléments du tableau.

Dans cet exemple :

foreach my $elm (@tab) {
  print $elm, ",";
}
print "\n";

On peut déclarer une variable ‘$elm‘, entre ‘foreach’ et la parenthèse ouvrante, qui représentera dans la boucle l’élément courant du tableau parcouru. Cette forme est la plus pratique pour les débutants ; c’est la moins implicite de toutes. A la moindre erreur rencontrée il faut se tourner vers cette forme. Car on peut tout à fait ne pas déclarer de variable pour manipuler l’élément courant. Dans la boucle l’élément courant sera représenté par la variable ‘$_‘. Cette variable est une variable implicite, une sorte de joker.

foreach (@tab) {
  print $_;
  print ",";
}
print "\n";

Et si c’est un joker cela veut dire que l’on peur se passer de l’écrire. Cette variable est implicitement passée en paramètre à toutes les fonctions internes du Perl si rien n’est précisé.

foreach (@tab) {
  print;
  print ",";
}
print "\n";

Ce mécanisme rends plus difficile la lecture de script à des non initiés. Son utilisation est vraiment une question d’habitude et une technique de feignasse (on préfère dans 90% des cas réfléchir que de taper trois caractères). C’est en grande partie ce pourquoi Perl est qualifié de Juste One Way language. Quoiqu’il en soit cela dépend surtout de qui le lit et de qui l’écrit.

Dans le même esprit pour pourrait afficher le tableau en le dépilant, grâce au mot clef shift...

while (@tab) {
  print shift @tab;
  print ",";
}
print "\n";

... le seul problème c’est que le tableau est vidé avec cette opération. shift enlève le premier élément du tableau et le renvoi.

Voici les équivalents de code si l’on veut afficher le tableau à l’envers :

my $i;
 
for ($i = $#tab; $i >= 0; $i--) {
  print $tab[$i], ",";
}
print "\n";
 
 
foreach my $elm (reverse @tab) {
  print $elm, ",";
}
print "\n";
 
 
while (@tab) {
  print pop @tab;
  print ",";
}
print "\n";
bash-2.05b$ ./test_tab.pl
cool,blah,blah,coucou,
cool,blah,blah,coucou,
cool,blah,blah,coucou,

Les tables de hash

Aussi appelées tableaux associatifs, les tables de hash sont pas très compliquées à utiliser. La principale difficulté d’emploi de ces structures est uniquement algorithmique. On n’a pas toujours l’idée de les utiliser. Pour ceux qui ne maîtrise pas ce type de mécanisme, il faut juste avoir à l’esprit qu’une table de hash contient des clefs uniques et ces clefs permettent d’obtenir des valeurs. Cette association clef ⇔ valeur peut simplifier la réalisation de script ou de programme.

Affectation

La clef doit toujours être une chaîne de caractères, l’utilisation d’un chiffre comme valeur peut-être utilise mais cela sera toujours moins efficace qu’un tableau que l’on accède via un indice.

my %hash;
 
$hash{weed} = "4kg";
$hash{'maroco'} = -1;
$hash{"au soleil"} = $une_variable;

Afficher une table de hash

Le mot clef ‘keys’ permet d’obtenir la liste des clefs contenu par une table de hash, ainsi on peut parcourir la table de hash et afficher chacune des associations clef ⇔ valeur.

foreach my $key (keys %hash) {
  print $k, " => ", $hash{$k}, "\n";
}

Effacer une valeur d'une table de hash

On peut avoir besoin d’effacer une valeur de la table de hash

undef $hash{weed};
#ou
$hash{weed} = undef;

Attention cette opération ne modifie que la valeur. La clef de cette valeur sera toujours présente dans la table de hash et donc la liste obtenue avec keys.

Effacer une clef d'une table de hash

delete $hash{weed};

La clef n’apparaîtra plus dans dans la liste obtenue avec keys.

Les structures conditionnelles et itératives

C’est dans cette section que l’on va vraiment pouvoir prendre l’ampleur de la richesse des mots clefs du langage. Cette éloquence est un désavantage en soi pour le PERL, elle rend difficiles la lecture d’un script aux novices. Nous allons essayer d’y voir plus clair.

Structures conditionnelles

La base et le minimum nécessaire dans un script c’est la structure conditionnelle. Pour explorer les différentes formes, nous allons décliner le même algorithme sous de multiples aspects.

Nous prendrons cet algorithme, un grand classique : avoir dans une variable la valeur la plus grande, d’un ensemble de variable. En gros on a deux variable ‘a’ et ‘b’ (‘$a’ et ‘$b’ en PERL) quelque soit la valeur de ‘a’ ou de ‘b‘, on veut avoir dans la variable ‘a’ la plus grande des valeurs.

Voici le canevas que nous utiliserons :

#!/usr/bin/perl -w
use diagnostics;
 
my $a = 5;
my $b = 8;
 
#algo
 
print "Max : $a\n";

A chaque fois nous modifierons que la partie : ‘#algo‘;

Différentes variétés

Traditionnelle

Voici la forme la plus classique :

if ($a < $b) {
  $a = $b;
}

Jusque ici pas de grande surprise, c’est une forme classique que l’on retrouve dans la plupart des langages. Après chaque instruction il y a un ‘;‘, comme en C, C++, Pascal, PHP... etc.

Toutefois il est possible d’écrire le BLOCK de la manière suivante :

if ($a < $b) {
  $a = $b
}

Il est noter que le ‘;’ a disparu. Pourtant cela fonctionne quand même... Pourquoi ?

Le ‘;’ a pour seul et unique but de séparer les instructions les unes des autres. Or pour ce cas il n’existe qu’une seule instruction dans le BLOCK d’instructions, donc il n’est pas impératif d’utiliser un séparateur (le ‘;‘).

Voici ce que l’on peut trouver dans perlsyn :

           if (EXPR) BLOCK
           if (EXPR) BLOCK else BLOCK
           if (EXPR) BLOCK elsif (EXPR) BLOCK ... else BLOCK

En utilisant cette forme : ‘if (EXPR) BLOCK‘. Il est obligatoire d’utiliser des ‘()’ et un BLOCK pour définir une structure conditionnelle sous cet aspect. Lorsque la documentation de PERL fait référence à un BLOCK cela se traduit par une utilisation explicite des ‘{}‘.

C’est pourquoi il n’est pas possible d’écrire cette forme conditionnelle sans les ‘{}‘, comme en C :

#Impossible en Perl
if ($a < $b)
  $a = $b;
#Ou encore impossible
if ($a < $b) $a = $b;

Si l’on tient, quoiqu’il en, soit à utiliser cette forme sur une ligne, il est encouragé d’employer cette forme si le BLOCK ne contient qu’une seule instruction :

if ($a < $b) {$a = $b}
Note sur les expressions

On aurait pu aussi écrire, en déclinant l’algèbre de Bool :

if (!$a > $b) {$a = $b}

Je pense que pour tous ceux qui ont eu un jour à lire du code ce problème d’omission de l’opérateur de négation. Perl dans sa richesse offre le choix des opérateurs de négation.

if (not $a > $b) {$a = $b}

Algorithmiquement on dire que ‘si ce n’est pas EXPR’ est équivalent à ‘a moins que EXPR

A moins que

Toujours dans la même logique de notre exemple, on aurait pu écrire :

unless ($a > $b) {$a = $b}

Le mot clef ‘unless’ se révèle très utiles dans bien des cas...

Instruction Conditionnelle

Il est courant d’avoir besoin de conditionner une instruction dans le but d’utiliser un aspect épurer des ‘()’ et des ‘{}‘, pour simplicité d’écriture. Cela signifie que l’on va inclure la condition dans l’instruction.

$a = $b if $a < $b;
#Ou encore :
$a = $b unless $a > $b;

Notez bien l’emplacement du ‘;‘.

Conclusion

On pourrait faire la démonstration suivante :

if (EXPR) BLOCK
if (EXPR) {STATEMENT;}
if (EXPR) {STATEMENT}
do {STATEMENT} if (EXPR);
STATEMENT if (EXPR);
STATEMENT if EXPR;

Si l’on maîtrise bien ces changements de formes on peut aisément comprendre que cette forme :

if ($a < $b) {
  $a = $b;
  $b = undef;
}

fait exactement la même chose que celle-ci :

$a = $b and $b = undef unless ($a > $b);

Opérateurs ternaires

Finalement c’est cette forme qui est la plus simple pour ce type d’algo... mais la moins drôle.

$a = ($a < $b) ? $a : $b;

Structures itératives

Rien de bien exceptionnels dans les boucles, on y retrouve la plus part des boucles standard : while, for, until et meme foreach qui vient du monde du script.

for ou foreach ?

C’est une grande question pour les programmeurs qui on fait beaucoup de C. Pour un parcours de tableau en perl le ‘foreach’ est entre 3 et 4 fois plus rapide que d’utiliser un ‘for‘. Cette différence est essentiellement du aux tableaux : Il est plus rapide d’accéder a tout les éléments un à un si le tableau est considéré comme une liste chaînée. Voici un petit script qui met en évidence la différence de temps d’exécution entre les différents types de boucles pour parcourir un tableau.

Consulter le script : For ou Foreach ? dans la section des cas d'écoles pour plus de détails techniques.

Perl 6

Attention ‘foreachdisparaît dans PERL 6. Il faut bien comprendre que :

foreach my $elm (@tab) {
  $r += $elm;
}

C’est la meme chose que ca :

for my $elm (@tab) {
  $r += $elm;
}

Il faut dès maintenant abandonner ‘foreach (@)’ au profit de ‘for (@)

Le squelette du langage

Bien que ce document s’adresse à des débutants en Perl, ce langage n’est pas adapté aux novices de la programmation. Il faut avoir un minimum de rigueur personnel pour arriver à exprimer sa pensée dans un script. C’est un peu comme de s’exprimer dans une langue vivante : Il vaut mieux réfléchir avant de parler. Bien sur tout est une question de contexte, quoiqu’il en soit c’est toujours plus simple lorsque l’on a le vocabulaire adapté. Le but du reste de cette section n’est pas d’offrir une nième explication sur les variables ou autres, mais d’apporter un peu de vocabulaire pour s’exprimer en perl avec justesse.

Contexte

Contrairement à d’autres langages le PERL possède dans sa grammaire des ambiguïtés. Selon les cas, on peut se retrouver dans l’obligation de préciser ce que l’on veut faire. Lors de l’utilisation d’une variable il faut tenir compte de deux facteurs :

  • La qualité de la variable : scalaire, tableau, hash, ref,... etc.
  • Le contexte où l’on l’utilise.

Scalaires et Listes

Prenons le tableau suivant :

my @tab = qw(a b c d e f);

Traduisons la pensée en Perl.
j’affiche un truc, si j’ai quelque chose dans mon tableau.

print "un truc\n" if @tab;

j’affiche mon tableau

print @tab, "\n";

On constate, sur ces cas, la simplicité avec laquelle on peut s’exprimer en perl. Mais pourquoi est-ce que ça marche ? Sans doute parce que l’algorithme à traduire en Perl est basique. Pourtant si je sors des contextes d’utilisations courants d’un tableau, est-ce aussi facile ?

j’affiche le nombre d’éléments que contient mon tableau.

Je me prends la tête

⇒ je passe par une étape intermédiaire : Je comptes le nombre d’éléments du tableau.

my $i = 0;
foreach (@tab) {$i++};
print $i, "\n";
#ou plus tordu
$i = 0
print map({$i++; $_ = ''} @tab), "$i\n";
Je lis un peu la doc et je me crois super fort

⇒ j’utilise la notation du dernière indice du tableau plus un.

print $#tab + 1, "\n";
Je me pose la bonne question

⇒ Pourquoi ca marche quand je fais ‘if @tab’ ? Regardons de plus près les définitions synoptiques de ‘if’ et de ‘print’ :

STATEMENT if EXPR;
print LIST;

Dans le premier cas nous somme dans une expression (EXPR) donc dans un contexte scalaire, dans l’autre nous somme dans un contexte de liste (LIST). Un contexte de liste n’est qu’une suite de scalaires consécutifs. Si l’on s’arrange pour changer le contexte où l’on utilise le tableau on résout notre problème. Utilisons une expression mathématique pour changer le contexte.

print @tab + 0, "\n";

Tout ceci n’est pas très joli. Il existe un mot clef pour expliciter le contexte scalaire : ‘scalar

print scalar @tab, "\n";

Il n’existe pas de mot clef pour forcer un contexte de listes, pour la simple et bonne raison que cela est inutile. L’imbrication de plusieurs contextes de listes peuvent être explicité par l’utilisation des ‘()’. Voici un cas où l’on a besoin de clarifier les contextes :

print "tab: ", join '|',  @tab, "\n";
# ne donne pas le meme resultat
print "tab: ", join('|',  @tab), "\n";

File handle

Rappel pour les incultes

Sous UNIX tout est fichier et ce qui ne l’est pas devrait l’être. Ce qui veut dire que tout objets, périphériques systèmes sont manipulables/accessibles comme un simple fichier. De ce fait les langages de programmation nés du monde UNIX ont besoin d’un système simple de manipulation des fichiers. En C (Sous Unix), ce sont des numéros, on est jamais sur d’avoir le même identifiant en ouvrant le même fichier.

Principe

Le PERL étant un langage plus linguiste, utilise des chaînes de caractères pour faire référence a un fichier. Donc les fonctions de manipulation de fichier de PERL, demande la plus part du temps comme argument un HANDLE ou en français un descripteur de fichier.

D’autre part en PERL, un HANDLE n’est pas seulement la référence au fichier mais aussi une représentation de son contenu.

Ouvrir un fichier

open HANDLE_OUT, ">mon_fichier" or die "mon_fichier:$!";
#ou encore
die "mon_fichier:$!" unless open(HANDLE_OUT, ">mon_fichier") ;

Bien sur une fois le traitement du file handle terminer il ne faut pas oublier de le fermer.

close HANDLE_OUT;

Écrire dans HANDLE

Il y plusieurs façon d’écrire dans un fichier. En voici une :

print HANDLE_OUT "Ma data qui tuxe";

Une erreur qui est courante dans l’utilisation de ces deux fonctions, c’est leur utilisation contradictoire. Ce qui me gêne le plus c’est cette virgule entre le file handle et le paramètre.

Pourtant tout s’explique lorsque l’on regarde les synopsis de ces deux fonctions :

print FILEHANDLE LIST
print LIST
open FILEHANDLE,EXPR

Comme print utilise un contexte de LIST, on ne peut pas utiliser de virgule pour séparer les paramètres.

Diamants

Pour lire les données d’un file handle on peut utiliser la fonction dérivée du système : read. Ou alors utiliser les diamonds ou autrement dit : <> que l’on place autour du file handle. Voici le comportement par défaut des diamants :

  • En contexte scalaire ⇒ la première ligne du file handle
  • En contexte liste ⇒ la totalité du file handle (Élément du tableau par ligne).

Ce comportement est définie par la variable magique de PERL : $/ ou $INPUT_RECORD_SEPARATOR ou $RS. Par défaut cette variable contient :

  • Sous UNIX ⇒ “\n”
  • Sous Windows ⇒ “\r\n”
  • Sous Mac ⇒ “\r” (Je suppose)

Donc un traitement ligne par ligne. Si l’on veut traiter un file handle caractère par caractère ou sur un caractère particulier voici ce que cela donnerait :

#!/usr/bin/perl -w
 
use strict;
 
open(HANDLE, "echo coucou |");
 
$/ = 'u';
while (<HANDLE>) {
  print;
  print "\n";
}
close HANDLE;
 
 
open(HANDLE, "echo coucou |");
 
$/ = \1;
while (<HANDLE>) {
  print;
  print "\n";
}
close HANDLE;

Voila la sortie du programme :

cou
cou


c
o
u
c
o
u



Il faut donc toujours avoir à l’esprit que les données du file handle sont toujours pre-maché par perl. Par exemple, si l’on a besoin d’utiliser la totalité du contenu d’un fichier sans avoir le besoin de le traiter ligne par ligne. Bref il ne faut surtout par faire ça :

open FILE, "mon_fichier";
my $data = '';
 
while (<FILE>) {
  $data .= $_;
}
close FILE;

Mais plutôt ce genre de chose :

open FILE, "mon_fichier";
my $RS_SAVE = $/;
$/ = undef;
$data = <FILE>;
close FILE;
 
#ou encore 
open FILE, "mon_fichier";
my $data;
{
  local $/ = undef;
  $data = <FILE>;
}
close FILE;

Note pour la performance

On pourrait croire qu’il est plus efficace de charger l’intégralité d’un fichier pour le traiter directement en mémoire. Ceci est valable pour un petit fichier, pour les gros volumes de données il vaut mieux traiter le fichier sur le flux.

Traitement memoire
open FILE, "mon_fichier" or die;
my @data = <FILE>;
close FILE;
for (@data) {
  print;
}

Il ne faut pas oublier de détruire le contenu de data pour éviter d’encombrer inutilement la mémoire :

@data = ();
#ou 
undef @data;
Traitement sur le flux
open FILE, "mon_fichier" or die;
while (<FILE>) {
  print;
}

Le plus efficace

Comme vous avez plus le constater la manipulation de fichiers peut se révéler assez lourde en fonction de la méthode que vous pouvez utiliser. Je pense surtout a la méthode open. Tout dépends de ce que vous voulez faire, par exemple une commande Unix.

cat

Cette commande Unix est la plus basique : elle ouvre tout les fichiers qu’elle en arguments et en écrit le contenu sur la sortie standard.

Approche open
#!/usr/bin/perl -w
 
use strict;
 
if (@ARGV) {
  for my $f (@ARGV) {
    if (open FILE, "$f") {
      while (<FILE>) {
	print;
      }
    } else {
      warn "$0: $f: $!\n";
    }
  }
} else {
  while (<STDIN>) {
    print;
  }
}
Approche Diamond
#!/usr/bin/perl -w
 
use strict;
 
while (<>) {
    print;
}

Conclusion

Il ne faut jamais oublier dans l’utilisation du PERL c’est que c’est melting pot de plusieurs façons de penser et de plusieurs philosophies. Voici comment traiterait la philosophie awk traiterait l’éternel problème des ^M ou \r dans un fichier avec perl :

perl -pi -e 's{\r$}{}' badfile.txt

Les fonctions

Comme dans tout langage il est possible de faire des fonctions. Comme en C c’est à la discrétion du programmer de rendre plus ou moins permissif le passage de paramètres.

Déclaration

sub func {
 print "ma fonction a moi\n";
}
 
func;
func();
&func;

Ce qui est amusant c’est que l’on peut appeler une fonction plusieurs manières. Cela pourrait être futile or pas du tout. La présence du ‘&’ permet de préciser que le symbole qui suit est bien une fonction. Dans l’exemple précédant il n’y pas de problèmes car la fonction est déclarée avant sont utilisation.

func;
func();
&func;
 
sub func {
 print "ma fonction a moi\n";
}

Dans cette exemple, si les ‘warning’ ainsi que ‘strict’ ne sont pas activé la fonction ne sera exécuté que deux fois :

$ /tmp/test_func.pl 
ma fonction a moi
ma fonction a moi

Quand rencontre la ligne ‘func;’ il ne peut pas déterminer si c’est ou non une fonction. Si vous voulez vous pouvez, grâce à ‘&‘, rendre la lecture de votre code plus accessible. Vous pouvez le rajouter devant l’appel de fonction si vous trouver que cela désambiguïse la compréhension du script.

Paramètres

Comme pour le reste en PERL, le passage de paramètres peut se faire de plusieurs manières. À chaque appel à une fonction, les variables passées en arguments sont copiées dans le tableau courant ou autrement dit en PERL ‘@_‘. Il suffit simplement de récupérer les éléments du tableau, dans la fonction.

sub func {
 print $_[2];
 print "\n";
}
 
&func('a', 'b', 'c', 'd');
$ ./test_func.pl
c

Cette méthode n’est pas très efficace pour la lisibilité et la compréhension du code. D’autre part pour les débutant, il est imperatif de déclarer les variables dans une fonction.

La duplication avec my

A mon avis, c’est ce qui est de plus facile à manier pour les débutants et suffisamment structuré pour éviter les erreurs typographiques. On est obligé, de déclarer les variables pour les utiliser. On trouve l’utilisation de cette syntaxe dans le module DBI6).

func {
 my ($var1, $var2, $var3, $var4) = @_;
 
 print $var1 + $var2, "\n";
 print $var3 * $var4, "\n"; 
}

Voici aussi un exemple dans le cas où l’on ne veut pas utiliser un argument passé en paramètre, par exemple pour éviter de le recopier encore une fois s’il occupe beaucoup de mémoire.

 my ($var1, undef, undef, $var4) = @_;

On peut aussi récupérer un tableau en paramètre pour peu qu’il soit seul ou le dernier.

func {
 my ($var, @tab) = @_;
 print join(',', @tab), "\n" unless defined $var;
}
 
&func(undef, 'a', 'b', 'c', 'd');
$ ./test_func.pl
a,b,c,d

Le shift du tableau courant

Cette méthode peut paraître verbeuse mais cette utilisation est très courante surtout dans les constructions objets.

func {
 my $var1 = shift;
 my $var2 = shift;
 my $var3 = shift;
 my $var4 = shift;
 
 print $var1 + $var2, "\n";
 print $var3 * $var4, "\n"; 
}

Avec ou sans ()

On peut s’interroger sur l’utilisation des parenthèses lors de l’appel d’une fonction en PERL. Certains pensent que de ne pas utiliser de parenthèses pour écrire une fonction est une manière de plus de rendre les scripts illisibles. En fait, il faut avoir a l’esprit que les parenthèses représentent un tableau anonyme, donc leur utilisation change le comportement du passage des paramètres aux fonctions. S’il n’y a pas de parenthèses la fonction prend automatiquement le tableau courant comme argument.

&func;
#Est equivalent a 
&func(@_);

‘&func’ n’est pas du tout la meme chose que ‘&func()‘.

Valeurs de retour

Avant de retourner une ou des valeurs dans une fonction on peut avoir besoin de savoir dans quel contexte la fonction a ete appelee. Grace a la fonction wantarray, ceci est possible.

contexte valeure
scalaire false
list/array true
void/indefini undef
return unless defined wantarray;   # On ne va pas plus loin si la valeur de retour n'est pas utilise
my @a = complex_calculation();
return wantarray ? @a : "@a"

Les références

Explication, description

Pourquoi ? Oui, pourquoi... Lorsque l’on débute en programmation le concept de références paraît toujours obscur. Je pense que c’est aussi une question de maturité, certains principes en programmation deviennent plus clairs avec le temps et la pratique. Les langages ont évolués avec le temps intégrant de nouveaux concepts. Ces concepts naissent d’une nécessité.

Les références sont à mon sens l’âge de raison7) pour les langages. Les précédentes générations de langages étaient les langages procéduraux. Ces derniers, au détour d’un algorithme, ont souvent besoin de manipuler des données à différents endroits du programme (fonction ou procédure). A chaque fois que l’on a besoin de cette donnée on va la copier. Voici un exemple en perl :

my @data = ('coucou', 3, 'blah', 'hihi', 4);  #<= 1 ere copie
 
sub func {
 my @d = @_;                               #<= 2 ere copie
 $d[1] += 2; 
 return @d;                                   #<= 3 ere copie
}
 
@data = func(@data);

Pour modifier un champ du tableau, nous avons été obligé de recopier 3 fois les données, ce qui pourrait être très problématique si ce tableau contenait un grand nombre d’éléments. Comment faire pour n’avoir le tableau qu’une seule fois en mémoire ? L’utilisation d’une variable globale. C’est sans doute pourquoi la plupart des langages autorisent la création de variable globale. Voici le même exemple mais en utilisant une méthode globale :

my @data = ('coucou', 3, 'blah', 'hihi', 4);  #<= 1 ere copie
 
sub func {
 $data[1] += 2; 
}
 
func();

Malheureusement, dans ce cas-là nous faisons toujours une copie du tableau et nous ne pouvons plus utiliser la fonction pour un autre tableau.

Définition

Utiliser une variable, c’est utiliser de la mémoire. Or on manipule la mémoire avec des adresses mémoires (0xquelque chose) et les variables via leurs noms. D’ailleurs c’est le but des variables de simplifier l’utilisation/l’accès à la mémoire. En PERL on peut connaître l’adresse mémoire d’une variable en antislachant/backslashant une variable.

\$a

Voici un exemple qui affiche l’adresse d’une variable :

#!/usr/bin/perl -w
 
use strict;
 
my $a = "coucou";
print \$a, "\n";

Vous obtiendrez :

SCALAR(0x814f5c4)

Voici le même exemple avec un tableau :

#!/usr/bin/perl -w
 
use strict;
 
my @a = (1..1000);
print \@a, "\n";
ARRAY(0x814f5dc)

En terme de volumétrie, il vaut mieux manipuler des références à des données que les données elles mêmes. Sinon on risque de les recopier.

On peut donc utiliser une variable (donc un scalaire) pour stocker une référence :

#!/usr/bin/perl -w
 
use strict;
 
my @a = (1..1000);
my $ref = \@a;
print $ref, "\n";
ARRAY(0x814f5dc)

Construction anonyme

Pour éviter de recopier les données (au moins a l’initialisation) il est possible de construire un tableau directement dans une référence. C’est ce que l’on appelle un tableau anonyme.

On peut créer un tableau anonyme :

my $array_ref = [];

Ou une table de hash anonyme :

my $hash_ref = {};

si on les affiche :

print "array: ", $array_ref, "\n";
print "hash: ", $hash_ref, "\n";

On obtiendra :

array: ARRAY(0x817aec0)
hash: HASH(0x817aecc)

En reprenant l’exemple précèdent, nous obtenons :

  • une fonction qui utilise les références donc qui peut être réutilisée pour d’autres tableaux
  • On ne recopie pas les données a l’initialisation, elles sont directement accessibles par une référence.
my $data = ['coucou', 3, 'blah', 'hihi', 4];  #Construction anonyme pas de copie
 
sub func {
 my $d = shift;
 ${$d}[1] += 2; 
}
 
func($data);

Manipulation

Référencement

Pour obtenir la reference d’une variable ce n’est pas bien compliqué il suffit de la précéder d’un backslash ‘\‘.

Pour chaque exemple il y aura aussi l’exemple avec la construction anonyme directe :

Scalaire

my $var = "coucou";
my $ref_var = \$var;
#Construction anonyme
my $ref_var = \"coucou";

Tableau

my @tab = ("coucou", "hihi");
my $ref_tab = \@tab;
#Construction anonyme
my $ref_tab = ["coucou", "hihi"];

Table de hash

my %hash = ( text => "coucou",
             size => 6
           );
my $ref_hash = \$hash;
#Construction anonyme
my $ref_hash = { text => "coucou",
                 size => 6
               };
;

Déréférencement

Pour le déréférencement c’est un peu plus compliqué. Il faut savoir que type de référence on veut utiliser :

Type Syntax
scalaire ${$ref}
tableau @{$ref}
hash %{$ref}

Les accolades sont volontairement rajoutées mais elles sont optionnelles, je pense que pour les débutants ou ceux qui ont un peu de mal c’est plus pratique. La syntaxe d’utilisation change complètement sans les accolades pour les tableaux et les tables de hash. Le fait d’avoir le choix de la syntaxe a un but. Pour le programmeur la syntaxe des références avec les accolades est une phase transitoire dans sa progression du langage. Une fois que les contextes d’utilisation sont bien maîtrisés on dérive naturellement (par flemme) vers la syntaxe sans accolade. Il ne faut pas oublier que la syntaxe avec accolades permet de résoudre des situations de contexte complexe.

Voici quelques exemples d’utilisation en reprenant les exemples du référencement :

Scalaire

print $var, "\n";
#avec la reference
print ${$ref_var}, "\n";
#sans les accolades
print $$ref_var, "\n";

Tableau

if (@tab) {
  print $tab[0], "\n";
}
#avec la reference
if (@{$ref_array}) {
  print ${$ref_array}[0], "\n";
#sans les accolades
  print $ref_array->[0], "\n";
}

Table de hash

for my $k (keys %hash) {
  print "$k => ", $hash{$k}, "\n";
}
#avec la reference
for my $k (keys %{$ref_hash}) {
  print "$k => ", ${$ref_hash}{$k}, "\n";
#sans les accolades
  print "$k => ", $ref_hash->{$k}, "\n";
}

Tableaux et références

Référence de Tableaux

my $tab = ['a', 0, 'c'];
print "Nombre d'elements dans le tableau: ", scalar @$tab, "\n";
#parcours
for my $e (@$tab) {
  print "elm: " , $e, "\n";
}
#ajout d'un element 
push @$tab, 2;
 
#Affichage d'un element du tableau 
print "elm: ", $tab->[0], "\n";
print "elm: ", $$tab[0], "\n";

Tableaux de références

Cette structure est très pratique pour gérer plusieurs propriétés d’un élément. Prenons l’exemple d’une liste de fichiers.

my @files = ();
#              Path    filename   size  chmod
push @files, ['/tmp', 'test.txt', 4103, 0644];
push @files, ['/var/tmp', 'test.doc', 719823, 0600];
for my $f (@files) {
  print join('/', @{$f}[0,1]), " (", $f->[2], " bytes)\n";
}

Référence de Tableaux de références

On peut aussi faire la même chose directement avec une référence de tableau.

my $files = [];
#              Path    filename   size  chmod
push