Article publié dans Linux Magazine 104, avril 2008.
Copyright © 2008 - Sébastien Aperghis-Tramoni
Après plusieurs années d'un long développement, Perl 5.10 est finalement sorti ce mardi 18 décembre, le jour du vingtième anniversaire de la sortie de Perl 1.0. Regardons un peu tout ce qu'apporte cette nouvelle version majeure.
Si les utilisateurs de Perl ont attendu plus longtemps que prévu cette nouvelle version, c'est déjà parce que comme pour la plupart des logiciels libres, le plan est de publier "quand c'est prêt". Bien sûr, des cycles se mettent assez naturellement en place, et dans le cas de Perl 5, il y avait une nouvelle version à peu près tous les ans ou tous les deux ans : les deux dernières majeures étaient la 5.6.0 en 2000 et la 5.8.0 en 2002. Bien sûr il avait des sous-versions, mais même la dernière, la 5.8.8, date de février 2006.
Une des raisons est que Perl 5.8 est très stable, et permet déjà de compenser ses points faibles et d'ajouter de nouvelles fonctionnalités par l'utilisation de modules du CPAN. Il n'y avait donc pas une forte pression de la part des utilisateurs (et donc des sociétés) pour une nouvelle version majeure. De plus, le développement de Perl 6 avait un temps jeté le trouble : y aurait-il de nouvelles versions de Perl 5 une fois Perl 6 disponible ?
La question a été tranchée de manière simple. En partant de la constatation que Perl 5 et Perl 6 sont deux projets totalement différents au niveau technique et architectural, il a été décidé que Perl 5 continuerait d'être maintenu et même amélioré tant qu'il y aurait des utilisateurs. Il s'est alors produit un déclic, et le développement est reparti de plus belle, en mettant l'accent sur la transition vers Perl 6 et pour ce faire sur l'ajout progressif de fonctionnalités inspirées du futur langage. Cela a au final allongé ce cycle de développement, mais le produit à l'arrivée est à la hauteur de l'attente.
Le nombre de nouveautés significatives pour les utilisateurs est
d'ailleurs suffisamment conséquent pour que nous ayons préféré
répartir leur description sur plus d'un article, afin que ceux-ci
restent digestes ;-)
Removed $*, $# pseudo-hashes compiler JPL Syntaxe defined-or say stackable file tests chdir, chmod and chown on filehandles smart match given..when variables d'état use features lexical $_ prototype _ UNITCHECK lexical pragmas Objects UNIVERSAL::DOES Hash::Util::FieldHash better support for inside-out objects new MRO: C3 Optimisations re-struct => less mem lighter constants faster UTF-8 ops faster creation of arrayref and hashref Security taint support in $AUTOLOAD, printf strlcat() and strlcpy() constified API Modules encoding::warnings Module::CoreList Math::BigInt::FastCalc is XS Compress::Zlib, IO::Zlib Archive::Tar Digest::SHA ExtUtils::CBuilder and ExtUtils::ParseXS < xsubpp Module::Build CPANPLUS, cpan2dist Misc Unicode 5.0.0 better diags better support for exotic OS
En premier lieu, certaines fonctionnalités anciennes ou expérimentales ont été supprimées car elles étaient peu fonctionnelles, voire posaient problème. Comme la plupart n'étaient pas vraiment employées, et étaient marquées expérimentales ou obsolètes, cela ne pose pas de véritable problème de compatibilité.
Tout d'abord, les variables spéciales $*
et $#
ont été supprimées.
La première était un vestige de Perl 4 équivalent à l'option /m
des
expressions régulières, la seconde une tentative d'émulation du format
OFMT
de awk. Les pseudo-hashes ne sont plus supportés, ce qui a
permit d'accélérer l'accès aux éléments des vrais hashes. Enfin le
compilateur Perl vers bytecode et C, ainsi que la passerelle Java-Perl
JPL, ont été supprimés (ils ne fonctionnaient pas, et il existe des
alternatives à JPL sur le CPAN, dont Inline::Java
).
La syntaxe de Perl 5.10 a été enrichie de plusieurs ajouts provenant de Perl 6. L'une des plus attendue est le fameux defined-or qui permet d'écrire correctement et de manière courte l'affectation d'une valeur par défaut :
$var = defined $input ? $input : $default; $option = $default unless defined $option;
devient maintenant
$var = $input // $default; $option //= $default;
La double barre oblique //
a été retenue comme symbole pour sa
ressemblance avec la double barre verticale ||
, ce qui permet de
se souvenir facilement que cela fait pareil, sauf que cela marche
dans tous les cas (puisque ||
ne sait pas différencier une valeur
fausse d'une valeur non définie).
say
Autre ajout venu de Perl 6, la fonction say
fonctionne comme print
,
mais en ajoutant un saut de ligne à la fin. C'est donc similaire à la
fonction println()
de Pascal et Java, mais en plus court, ce qui est
utile pour les unilignes (et les adeptes du golf).
say "OH HAI"; # équivalent à : print "OH HAI\n"
On peut noter deux petits ajouts en matière d'opérations sur les fichiers.
D'une part, on peut maintenant empiler les tests comme -f
, -s
, ce qui
permet de gagner en concision. Ainsi, pour vérifier qu'un chemin est un
fichier accessible en écriture et exécution, on pourra écrire
-f -w -x $file
là où il fallait écrire -f $file && -w _ && -x _
.
D'autre part, les fonctions chdir()
, chmod()
et chown()
fonctionnent maintenant sur les descripteurs de fichiers si votre système
le permet.
Encore une fonctionnalité importée de Perl 6, le smart match
ou comparaison avancée.
Derrière ce nouvel opérateur booléen ~~
se cache un mécanisme assez
puissant mais pas totalement facile à maîtriser, qui permet de comparer
deux éléments de manière totalement générique. On ne peut guère que
traduire et commenter la table de correspondance de perlsyn
qui
détaille son fonctionnement en fonction du type de chaque opérande.
Il faut noter à l'avance que cet opérateur est toujours commutatif
($a ~~ $b
est toujours équivalent à $b ~~ $a
) et que la première
règle de la table qui s'applique détermine son comportement.
Type $a Type $b Type de correspondance Code équivalent ======= ======= ====================== =============== code[1] code[1] égalité des références $a == $b autre code[1] scalar sub truth $b->($a) hash hash clés de hash identiques [sort keys %$a]~~[sort keys %$b] hash tableau existence d'une tranche grep {exists $a->{$_}} @$b hash regex grep des clés du hash grep /$b/, keys %$a hash autre existence d'une entrée exists $a->{$b} tableau tableau tableaux identiques[2] tableau regex grep du tableau grep /$b/, @$a tableau nombre nombre dans tableau grep $_ == $b, @$a tableau autre chaîne dans tableau grep $_ eq $b, @$a autre undef indéfini !defined $a autre regex correspondance de motif $a =~ /$b/ code() code() résultats identiques $a->() eq $b->() autre code() simple closure truth $b->() # $a est ignorée nombre nombre[3] égalité numérique $a == $b autre chaîne égalité de chaîne $a eq $b autre nombre égalité numérique $a == $b autre autre égalité de chaîne $a eq $b
[1] Ce doit être une référence de code dont le prototype (s'il existe)
n'est pas vide. Les fonctions avec un prototype vide sont traitées par
les règles code()
.
[2] C'est-à-dire que chaque élément correspond à l'élément de même index dans l'autre tableau. Si une référence circulaire est détectée, on revient à l'égalité des références.
[3] Un vrai nombre ou une chaîne qui ressemble à un nombre.
Le code équivalent indiqué dans cette table n'est bien sûr que pour illustrer, le véritable code s'arrêtant dès que c'est possible.
On le voit, si certaines règles sont simples à comprendre, d'autres sont déjà plus subtiles. On voit néanmoins que certaines opérations qui avant demandaient pas mal de code vont s'en trouver simplifiées. Ainsi, pour vérifier si deux tableaux sont identiques :
say "ces tableaux sont ", \@a ~~ \@b ? "identiques" : "différents";
given .. when
Perl 5.10 propose une construction similaire au switch
présent dans
bien des langages, mais ici bien plus puissante car, s'appuyant sur la
comparaison avancée, elle permet des tests bien plus complexes que ceux
possibles avec switch
. Plus exactement, cette construction se compose
ainsi :
given (EXPR)
affecte la valeur de l'expression à $_
.
when (EXPR)
évalue l'expression comme une condition booléenne.
La manière exacte d'évaluer cette condition dépend de ce que contient
l'expression, mais en général, given($value)
est équivalent à
given($_ ~~ $value)
. Il y a plusieurs exceptions indiquées dans
perlsyn
mais on peut résumer en disant que cela fonctionne généralement
comme on s'y attend.
default
correspond comme on peut s'y attendre aux autres cas, si
aucune condition when
n'a été vérifiée.
Pour simplifier l'utilisation, lorsqu'une condition when
se vérifie,
on sort du given
en même temps que du bloc correspondant. C'est
l'inverse du switch
en C où il faut explicitement indiquer break
en fin de chaque case
. On peut toutefois contrôler plus finement le
flux d'exécution avec les mots-clés break
pour sortir du given
et continue
pour transférer l'exécution au when
suivant. Bien
sûr, les conditions when
sont examinées dans l'ordre, et c'est la
première qui se vérifie qui est exécutée.
Cela peut paraître complexe, mais c'est en fait assez naturel et on
peut aussi bien reproduire le switch
du C :
given ($number) { when (42) { say "La Réponse" } when (56) { say "fer standard" } }
que le case..esac
du Bourne shell (sauf qu'on peut utiliser des
expressions régulières) :
use Regexp::Common qw/net/; given ($host) { when ("localhost" ) { say "adresse locale" } when (/$RE{net}{IPv4}/ ) { say "adresse IPv4" } when (/$RE{net}{domain}/) { say "FQDN" } default { say "type d'argument inconnu" } }
Mais l'intérêt réside bien sûr dans l'exploitation du smart match, et du fait qu'on n'est nullement limité dans le type des arguments et des données de comparaison.
my @primes = ( 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97 ); given ($value) { when ( undef ) { say "valeur non définie" } when ( 42 ) { say "La Réponse" } when ( $_ >= 0 && $_ < 100 ) { when ( @primes ) { say "petit nombre premier" } default { say "n'est pas un petit nombre premier" } } when ( /$RE{net}{IPv4}/ ) { say "adresse IPv4" } when ( \&is_leap_year) { say "$value est une année bissextile" } default { say "type de valeur non géré" } }
L'exemple est bien sûr un peu artificiel, mais il montre déjà une partie
des possibilités de comparaison de cette nouvelle construction, et
illustre le fait qu'on peut même imbriquer les when
.
Il faut par contre noter que suite à des problèmes pour partie techniques,
l'opérateur de comparaison avancé et given .. when
, bien qu'à la base
inspirés par Perl 6, sont au final différents de leurs équivalents
dans le futur langage, tant sur le plan de la syntaxe que sur le plan
des sémantiques. Par exemple, le ~~
de Perl 5.10 est commutatif
alors qu'en Perl 6 ce n'est pas le cas, et la gestion des tableaux
est assez différente.
Plus ennuyeux, cela ne marche pour le moment qu'avec les données de base.
Les objets, la surcharge et en général la magie ne fonctionnent pour le
moment pas avec la comparaison avancée (et donc given .. when
),
qui regarde actuellement la structure sous-jacente au lien d'invoquer
les appels corrects.
Pour répondre à certains besoins, une nouvelle classe de variables a été
introduite, les variables d'état. Déclarées avec le mot-clé state
,
elles sont comme les variables my
seulement visibles dans leur portée
lexicale, mais contrairement à ces dernières, leur valeur est persistante
et se conserve d'un appel sur l'autre. Elles sont donc comparables aux
variables static
en C. Petit exemple trivial qui affiche les cinq
premières puissances de 2 :
sub next_power { state $x = 1; # n'est affecté qu'au premier appel return $x <<= 1 } say next_power() for 1..5
Avant, on aurait utilisé un fermeture pour ce genre de code. Cela marchait
bien (et cela marche toujours), mais state
permet d'éviter certains
coûts en mémoire et en complexité associés aux fermeture.
Cela fonctionne aussi pour les tableaux et les hashes, mais on ne peut dans ce cas pas réaliser d'affectation initiale.
accumulate($_) for 1..5; sub accumulate { state @values; my $value = shift; push @values, $value; say "values: @values"; }
Par contre, pas de problème avec les objets :
use IO::File; log_msg("OH HAI"); log_msg("IM IN UR LOG"); log_msg("KTHX BAI"); sub log_msg { state $fh = new IO::File "mylog", "w"; my $msg = shift; $fh->print("$msg\n"); }
Comme certaines de ces nouvelles fonctionnalités pourraient casser du code
existant, elles sont désactivées par défaut, et peuvent être activées à
la demande avec la pragma lexicale C
Pour les unilignes, l'option C<-E> est équivalente à C<-e>, mais active
aussi les ajouts de S
perl -E 'say "OH HAI WORLD"'
$_
lexicalLa variable $_
peut maintenant être lexicalisée avec my
, afin d'être
sûr de limiter des modifications à cette variable au seul bloc lexical de
travail.
_
Le prototype _
a été ajouté. Il est équivalent au prototype $
mais
utilisera $_
si aucune variable n'est passée en argument. Pour cette
raison, il ne peut être utilisé qu'en fin de prototype ou avant un
point-virgule.
UNITCHECK
Les adeptes de vérification poussée ou de code automodifiant disposent
maintenant des blocs UNITCHECK
, similaires aux blocs CHECK
(ils
sont exécutés en fin de la phase de compilation de l'unité qui les
définit), mais qui sont exécutés durant les évaluations dynamiques
alors que les blocs CHECK
ne l'étaient que durant la phase de
compilation initiale.
Il est maintenant possible d'écrire facilement des pragmas lexicales,
c'est-à-dire qui se comportent comme strict
et warnings
et
limitent leurs effets aux blocs lexicaux d'où elles sont invoquées.
Cela consiste principalement à utiliser le hash %^H
pour stocker
son état au moment de la compilation, et à le récupérer plus tard,
à l'exécution, grâce à caller()
.
Rafaël Garcia-Suarez a écrit la pragma encoding::source
à la fois
à titre d'exemple, et aussi pour remplacer la pragma encoding
jugée
insatisfaisante. Cela permet de mélanger au sein d'un même fichier
du texte écrit dans différents encodages :
use encoding::source "utf8"; # le code écrit ici est en UTF-8 { use encoding::source "latin-1"; # mais celui dans ce bloc est en ISO-Latin-1 } # et là on revient en UTF-8
À utiliser avec parcimonie, pour éviter de s'arracher les cheveux !
Voir aussi perlpragma
et la documentation de caller()
pour
plus de détails concernant l'implémentation des pragmas lexicales.
Le modèle objet de Perl n'a pas été fondamentalement changé, et reste toujours aussi simple (voire simpliste), mais a été amélioré afin d'offrir un meilleur support pour les nouveaux modèles qui se sont développés ces deux dernières années. En effet, les systèmes d'objet inversés (inside-out objects), les rôles et autres méta-modèles se sont appuyés sur le modèle objet existant, au détriment de la performance. Perl 5.10 a intégré certains des mécanismes sous-jacents afin de simplifier le code de ces nouveaux modèles.
UNIVERSAL::DOES
La méthode globale DOES()
a été ajoutée afin de pallier les
problèmes de sémantique et d'utilisation de UNIVERSAL::isa()
,
et de fournir un support plus général. Plus précisément, isa()
a une sémantique de vérification d'héritage de classes, alors que
DOES()
(prévue pour être facilement surchargée), se contente
de vérifier si un objet ou une classe fait quelque chose, ce
qui est plus adapté pour établir des relations entre classes et
rôles. On peut donc s'en servir aussi bien en remplacement de
isa()
pour vérifier qu'un objet hérite d'une classe donnée :
if ( $object->DOES($parent_class) ) { ... }
que pour vérifier qu'une classe implémente bien un rôle donné :
if ($debbie->DOES("Dalek")) { $debbie->exterminate; }
Hash::Util::FieldHash
Ce module a été écrit et intégré à Perl 5.10 afin d'offrir un
meilleur support des objets inversés. En soi, ce module n'offre que
peu d'intérêt hormis pour ceux qui veulent écrire un système objet
avancé. En effet les problèmes typiquement rencontrés sont la gestion
des références aux véritables attributs, la libération de mémoire
à la destruction de l'objet (comme les attributs ne sont plus dans
l'objet, ils ne disparaissent plus avec lui) et le support des
threads. Hash::Util::FieldHash
fournit les fonctions permettant
de répondre à ces problèmes.
À noter que le module Hash::Util::FieldHash::Compat
, disponible
sur le CPAN, permet d'émuler cette nouvelle API sur les précédentes
version de Perl.
D'abord, un peu de terminologie. C3 est un algorithme de résolution des méthodes ou MRO (method resolution order), c'est-à-dire un algorithme permettant de déterminer un ordre pour traverser la hiérarchie des classes afin de déterminer la bonne méthode à exécuter.
L'exemple classique est une hiérarchie de classe en losange, où la
classe D
hérite des classes B
et C
qui elles-mêmes héritent
de la classe A
.
A / \ B C \ / D
L'algorithme classique de résolution des méthodes en Perl effectue
une recherche par profondeur (depth first search ou DFS), et
renvoie donc les classes dans l'ordre (D, B, A, C)
. Le problème
est que A
apparaît avant C
alors que cette dernière est une
sous-classe de A
. C3 en revanche fournit un ordre plus correct
(D, B, C, A)
.
L'algorithme C3 est une linéarisation conçue pour éviter qu'une
classe n'apparaisse avant une de ses sous-classes en préservant à
tout moment une triple cohérence sur l'ordre de précédence locale,
le graphe de précédence étendu et la monotonie (d'où le nom de C3).
Originellement implémenté en Dylan, il a été adopté comme MRO par
défaut dans Python depuis la version 2.3, et était disponible en
Perl 5.8 avec le module Class::C3
. Directement intégré dans
Perl 5.10, il est plus rapide et plus facilement contrôlable par
la pragma mro
qui permet de sélectionner la méthode de recherche :
use mro "dfs"; # utilise le MRO DFS pour cette classe use mro "c3"; # utilise le MRO C3 pour cette classe
À noter que pour raison de compatibilité arrière, DFS reste le MRO activé par défaut.
De manière moins visible pour l'utilisateur, Perl 5.10 a été l'objet d'un énorme chantier de nettoyage interne du code source, dont certaines parties ont maintenant 20 ans d'âge. En particulier, Nicholas Clark, pumpking de 5.8, a effectué un gros travail pour factoriser plusieurs structures internes (typeglobs, GVs, CVs, formats), permettant de gagner quelques octets par ci ou par là, démultipliés par leur fréquence d'utilisation. En conséquence, un même programme Perl doit consommer moins de mémoire avec Perl 5.10 qu'avec 5.8.
Durant ce travail de factorisation des structures, Nicholas en a
profité pour modifier la manière dont sont gérées les constantes et
elles sont maintenant plus légères (près de 400 octets gagnés) et un
peu plus rapides. Le module constant.pm
a de plus été modifié par
votre serviteur et publié sur le CPAN pour qu'il soit fonctionnel sur
Perl 5.5, ce qui permet de profiter de certaines fonctionnalités
qui n'étaient disponibles que depuis 5.8.
Certains cas spéciaux de la fonction sort()
ont été optimisés, par
exemple @a = sort @a
qui évite maintenant de créer un tableau
intermédiaire. De même reverse sort ...
effectue maintenant le
tri directement en ordre inverse. D'autres cas ont été pris en compte
afin de prendre moins de mémoire et de les rendre un peu plus rapides.
Il est par ailleurs possible d'utiliser une fonction récursive comme
tri personnalisé pour sort()
.
Les opérations internes de gestion d'Unicode sont plus rapides. En particulier, le cache est maintenant plus efficace et plus souvent utilisé.
La création de références à des tableaux et listes vides est un cas spécial, maintenant plus rapide.
La sécurité n'est pas en reste avec quelques nouveautés destinées à
nous protéger des problèmes actuels. Ainsi, la variable $AUTOLOAD
supporte maintenant correctement le traçage des valeurs quand le
taint mode est activé. De même, les fonctions printf()
et
sprintf()
ont été modifiées pour rejeter tout argument reconnu
comme non fiable.
En interne, Perl utilise maintenant les fameuses fonctions
strlcat()
et strlcpy()
introduites par les développeurs
d'OpenBSD, et toute l'API interne et externe a été revue afin de
spécifier comme constantes toutes les chaînes qui pouvaient l'être.
L'intérêt est de fournir plus de sémantique au compilateur afin
qu'il puisse effectuer davantage de vérifications, ce qui permet
de se prémunir de certains problèmes. Cela facilite aussi la
compilation sur les compilateurs les plus avancés, qui sont souvent
plus tatillons.
Un grand nombre de modules font leur apparition dans la distribution standard (la majeure partie existent sur le CPAN depuis plusieurs années). Petite revue des plus intéressants.
Module::CoreList
et sa commande corelist
permettent de savoir
dans quelle version de Perl un module a été introduit.
Archive::Tar
permet comme son nom l'indique de créer et manipuler
des archives au format Unix tar(1)
en pur Perl, ce qui est utile
sur les systèmes qui ne disposent pas de cette commande. Avec
Compress::Zlib
, qui est un module permettant de manipuler des
flux gzip
, on peut créer et extraire des distributions au
format habituel.
Module::Pluggable
est un module permettant de gérer facilement
un système de plugins.
Pod::Simple
est le nouveau moteur d'analyse du Pod, le format
de documentation de Perl. Plusieurs des modules et outils pour
transformer et afficher le Pod ont été modifiés pour l'utiliser
à la place de leurs propres analyseurs.
encoding::warnings
est une pragma lexicale qui produit des avertissements
chaque fois qu'une chaîne de caractères ASCII contenant des caractères
étendus est implicitement convertie en UTF-8.
La commande xsubpp
, qui transforme les fichiers XS en C, a été
factorisé en deux modules, ExtUtils::ParseXS
et ExtUtils::CBuilder
.
Module::Build
est un nouvel environnement de construction des
distributions CPAN, destiné à remplacer ExtUtils::MakeMaker
qui
dépend de l'utilitaire make(1)
. Étant en pur Perl et orienté objet,
il a été conçu pour pallier un des gros problèmes de ExtUtils::MakeMaker
,
à savoir la difficulté pour le personnaliser.
CPANPLUS
est une API permettant de manipuler les distributions
et miroirs CPAN. Sur ce point, il constitue avec sa commande cpanp
un
remplaçant plus modulaire au traditionnel shell CPAN.pm
, qui a lui-même
subit de nombreuses améliorations. Mais CPANPLUS
permet d'ajouter plus
facilement de nouvelles fonctionnalités comme l'interrogation des tickets
ouverts liés à un module, ou la transformation des distributions CPAN
en paquets RPM ou Debian avec la commande cpan2dist
.
Inversement, de nombreux modules qui n'étaient avant disponibles que
dans la distribution standard sont maintenant aussi sur le CPAN :
XSLoader
, Sys::Syslog
, threads
, threads:shared
, Exporter
,
File::Path
, constant
. Et bien sûr, tous les modules déjà en double
vie comme CPAN.pm
, Tie::HiRes
, Math::BigInt
, Math::Complex
,
Test::More
, ExtUtils::MakeMaker
, etc, ont été mis à jour avec
leur plus récente version.
Dans les autres changements notables, on peut noter que Perl 5.10
intègre la base de données des caractères Unicode 5.0.0, et propose
des messages de diagnostic plus clairs. En particulier, Perl essayera
d'indiquer le nom de la variable dans le message "Use of uninitialized
value"
("essayera" car ce n'est pas toujours possible, par exemple
si vous faites des choses bizarres avec les fermetures).
Le support pour les systèmes d'exploitation anciens ou exotiques a été amélioré, pour s'accorder avec leur spécificités. Par exemple l'EBCDIC, toujours utilisé sur les mainframes IBM (OS/390, z/OS, etc). Perl s'intègre aussi mieux aux nouveaux environnements OpenVMS et sait tenir compte des nouvelles fonctionnalités de la CRTL et d'ODS-5 (le système de fichiers d'OpenVMS).
Windows n'est pas en reste avec entre autres le support des noms
Unicode quand c'est possible (sur les partitions NTFS) et une variable
${^WIN32_SLOPPY_STAT}
qui permet d'accélérer notablement la fonction
stat()
. C'est très utile pour Cygwin où les accès au système de
fichiers sont encore plus lents que les accès natifs Win32.
Malgré ce long inventaire à la Prévert, nous n'avons abordé qu'une
partie des changements de Perl 5.10, ceux considérés comme les plus
importants ou intéressants. Le lecteur curieux est invité à lire
perl5100delta
pour une description plus exhaustive et détaillée.
Le prochain article sera consacré au gros morceau de Perl 5.10, les
évolutions des expressions régulières.
Sébastien Aperghis-Tramoni <sebastien@aperghis.net> - Sophia.pm
Merci aux Mongueurs de Perl et à Rafaël Garcia-Suarez pour leur relecture et leurs suggestions.
Copyright © Les Mongueurs de Perl, 2001-2011
pour le site.
Les auteurs conservent le copyright de leurs articles.