1. Introduction▲
1-1. Perl 6, c'est quoi?▲
Perl 6 est un langage de haut niveau, générique et dynamique. Il supporte plusieurs paradigmes dont : la programmation procédurale, la programmation orientée objet et la programmation fonctionnelle.
La devise de Perl 6 :
- TMTOWTDI (prononcé Tim Toady) : There is more than one way to do it: c'est-à-dire « Il y a plus d'une façon de le faire ».
- Easy things should stay easy, hard things should get easier, and impossible things should get hard: « Les choses faciles doivent rester faciles, les choses difficiles devraient devenir plus faciles, et les choses impossibles devraient devenir difficiles ».
Un programme ou script Perl 6 est un fichier texte qui sera compilé et exécuté par l'exécutable perl6 et la machine virtuelle associée (par exemple MoarVM ou JVM).
1-2. Jargon▲
- Perl 6 est une spécification de langage avec une suite de tests. Les implémentations qui passent la suite de tests sont considérées comme du Perl 6.
- Rakudo est un compilateur pour Perl 6.
- Rakudobrew est un gestionnaire d'installation pour Rakudo.
- Panda est un installeur de modules pour Perl 6.
- Rakudo Star est un paquet qui comprend : Rakudo, Panda, une collection de modules, et de la documentation.
1-3. Installer Perl 6▲
Linux
- Installez Rakudobrew : https://github.com/tadzik/rakudobrew.
- Installez Rakudo : tapez la commande suivante dans le terminal rakudobrew build moar.
- Installez Panda : tapez la commande suivante dans le terminal rakudobrew build panda.
OS X
Quatre solutions possibles :
- Suivez les mêmes étapes que celles indiquées pour l'installation sur Linux, ou
- Installez avec homebrew : brew install rakudo-star, ou
- Installez avec MacPorts : sudo port install rakudo, ou
- Téléchargez l'installateur (fichier avec l'extension .dmg) depuis http://rakudo.org/downloads/star/
Windows
- Téléchargez l'installeur le plus récent (fichier avec une extension .MSI) de http://rakudo.org/downloads/star/.
Si votre système possède une architecture 32 bits, téléchargez le fichier x86. S'il possède une architecture 64 bits, téléchargez le fichier x86_64. - Après l'installation, ajoutez C:\rakudo\bin à votre PATH.
Docker
- Obtenez l'image officielle docker pull rakudo-star.
- Ensuite exécutez dockerrun -it rakudo-star.
1-4. Exécuter du code Perl6▲
On peut exécuter du code Perl 6 en utilisant le terminal Perl 6 interactif REPL (Read-Eval-Print Loop). Pour ce faire, ouvrez un terminal, tapez perl6 dans la fenêtre de terminal et ensuite la touche [Entrée].
Une invite de commande > apparaîtra.
Ensuite, tapez une ligne de code puis la touche [Entrée]. Le REPL affichera la valeur de la ligne interprétée. Vous pouvez taper une autre ligne, ou exit et ensuite [Entrée] pour sortir du REPL.
L'autre façon consiste à écrire votre code dans un fichier, le sauvegarder puis l'exécuter. Il est conseillé, pour plus de clarté, que les scripts Perl 6 portent l'extension .pl6. Exécutez le fichier en entrant perl6 nom-du-fichier.pl6 dans la fenêtre de terminal (puis [Entrée]).
À l'inverse du REPL, le résultat ne sera pas automatiquement affiché pour chaque ligne : le code doit contenir une instruction comme say ou print pour afficher une sortie.
Le REPL est la plupart du temps utilisé pour essayer un morceau de code, le plus souvent une seule ligne. Pour des programmes de plus d'une seule ligne, la méthode fichier/exécution est recommandée.
Les lignes de code unilignes peuvent aussi être entrées de façon non interactive sur la ligne de commande en tapant perl6 -e 'mon code ici' et ensuite [Entrée].
Rakudo Star fournit un éditeur ligne par ligne, qui augmente les fonctionnalités du REPL. Comme : le rappel des commandes par les flèches « haut/bas », l'édition avec les flèches « gauche/droite » et la complétion avec la touche [TAB].
Si vous avez seulement installé Rakudo au lieu de Rakudo Star, vous n'aurez probablement pas les fonctions d'édition ligne par ligne. Lancez la commande suivante sur votre terminal pour y avoir accès :
- panda install Linenoise : fonctionne sur Windows, Linux et OS X
- panda install Readline : si vous êtes sur Linux et préférez la bibliothèque Readline
1-5. Éditeurs▲
Comme la plupart du temps, nous allons écrire et stocker nos programmes en Perl 6 dans des fichiers, nous devrions avoir un éditeur de texte décent qui reconnaît la syntaxe de Perl 6.
Je recommande personnellement Atom. C'est un éditeur de texte moderne livré avec une coloration syntaxique pour Perl 6. Perl6-fe est une coloration syntaxique alternative pour Perl 6 sur Atom, basée sur l'originale, mais comprenant de nombreux correctifs et ajouts.
D'autres personnes de la communauté utilisent aussi Vim, Emacs ou Padre.
Les versions récentes de Vim sont livrées avec la coloration syntaxique pour Perl 6. Emacs et Padre nécessiteront l'installation de paquets supplémentaires.
N'importe quel éditeur de texte peut être utilisé pour écrire ou lire un programme Perl ou Perl 6.
1-6. Bonjour Monde !▲
Nous allons commencer avec le rituel hello world.
say
'Bonjour Monde'
;
qui peut aussi s'écrire:
'Bonjour Monde'
.say
;
1-7. Aperçu de la syntaxe▲
Perl 6 a une forme libre : vous êtes libre (la plupart du temps) d'utiliser n'importe quelle quantité d'espaces.
Les instructions sont typiquement une ligne logique de code, elles doivent se terminer par un point-virgule :
say "Hello" if True;
Les expressions sont un type spécial d'instructions qui retournent une valeur :
1+2 retourne 3
Les expressions sont faites de termes et d'opérateurs.
Les termes sont des :
- variables : une valeur qui peut être manipulée ou changée ;
- valeurs littérales : une valeur constante comme un nombre ou une chaîne.
Les opérateurs sont classés en types :
Type |
Explication |
Exemple |
---|---|---|
Préfixé |
Avant le terme |
++1 |
Infixé |
Entre deux termes |
1+2 |
Suffixé |
Après le terme |
1++ |
Circonfixé |
Autour du terme |
(1) |
Postcirconfixé |
Après un terme, autour d'un autre |
Array[1] |
1-7-1. Identificateurs▲
Les identificateurs sont le nom donné aux termes lors de leur définition.
Règles :
- ils doivent commencer par un caractère alphabétique ou un tiret bas (underscore) ;
- ils peuvent contenir des chiffres (à l'exception du premier caractère) ;
- ils peuvent contenir des tirets ou des apostrophes (sauf le premier et le dernier caractère), mais avec un caractère alphabétique à droite de chaque tiret apostrophe.
Valide |
Non valide |
---|---|
var1 |
1var |
var-one |
var-1 |
var'one |
var'1 |
var1_ |
var1' |
_var |
-var |
Conventions de nommage :
- Camel: variableNo1
- Kebab: variable-no1
- Snake: variable_no1
Vous êtes libre de nommer vos identificateurs comme vous le souhaitez, mais, pour des raisons de cohérence et de lisibilité, il est recommandé de choisir une convention de nommage et de s'y tenir.
L'utilisation de noms signifiants facilitera votre vie et celle des autres.
var1 = var2 * var3 est syntaxiquement correct, mais son but n'est pas évident.
salaire-mensuel = salaire-journalier * jours-travaillés serait une meilleure façon de nommer vos variables.
1-7-2. Commentaires▲
Un commentaire est du texte ignoré par le compilateur.
Il y a trois types de commentaires :
-
ligne unique :
Sélectionnez#Ceci est une seule ligne de commentaire
-
intégré :
Sélectionnezsay
#`(Ceci est un commentaire intégré)
"Bonjour Monde."
Le caractère « ( » après #` définit le début du commentaire, le commentaire se termine avec une parenthèse fermante. On peut de même utiliser des crochets ou accolades, ou même des combinaisons de ces caractères.
- multiligne:
=begin
comment
Ceci est un commentaire sur plusieurs lignes.
Commentaire 1
Commentaire 2
=end
comment
1-7-3. Guillemets▲
Les chaînes doivent être délimitées par des guillemets droits, doubles ou simples (apostrophes).
Utilisez toujours des guillemets droits doubles :
- si votre chaîne contient une apostrophe ;
- si votre chaîne contient une variable qui doit être interpolée.
say
'Bonjour Monde'
; # Bonjour Monde
say
"Bonjour Monde"
; # Bonjour Monde
say
"Quelqu'un m'a dit"
; # Quelqu'un m'a dit
my $nom
=
'François Pinon'
;
say
'Salut $nom'
; # Salut $nom
say
"Salut
$nom
"
; # Salut François Pinon
Il est cependant possible de « protéger » un guillemet dans une chaîne entre guillemets (ou une apostrophe dans une chaîne entre apostrophes) à l'aide du caractère d'échappement \ :
say
'Quelqu
\'
un m
\'
a dit'
; # Quelqu'un m'a dit
2. Opérateurs▲
Opérateur |
Type |
Description |
Exemple |
Résultat |
---|---|---|---|---|
+ |
Infixé |
Addition |
1 + 2 |
3 |
- |
Infixé |
Soustraction |
3 - 1 |
2 |
* |
Infixé |
Multiplication |
3 * 2 |
6 |
** |
Infixé |
Puissance |
3 ** 2 |
9 |
/ |
Infixé |
Division |
3 / 2 |
1.5 |
div |
Infixé |
Division entière (arrondit vers le bas) |
3 div 2 |
1 |
% |
Infixé |
Modulo (reste de la division entière) |
7 % 4 |
3 |
%% |
Infixé |
Divisibilité |
6 %% 4 |
False |
6 %% 3 |
True |
|||
gcd |
Infixé |
Plus grand dénominateur commun |
6 gcd 9 |
3 |
lcm |
Infixé |
Plus petit commun multiple |
6 lcm 9 |
18 |
== |
Infixé |
Égalité |
9 == 7 |
False |
!= |
Infixé |
Inégalité |
9 != 7 |
True |
< |
Infixé |
Plus petit |
9 < 7 |
False |
> |
Infixé |
Plus grand |
9 > 7 |
True |
<= |
Infixé |
Plus petit ou égal |
7 <= 7 |
True |
>= |
Infixé |
Plus grand ou égal |
9 >= 7 |
True |
eq |
Infixé |
Égalité (chaînes) |
"Tintin" eq "Tintin" |
True |
ne |
Infixé |
Inégalité (chaînes) |
"Tintin" ne "Titine" |
True |
= |
Infixé |
Affectation |
my $var = 7 |
Attribue la valeur 7 a la variable $var |
~ |
Infixé |
Concaténation |
9 ~ 7 |
97 |
"Bonjour " ~ "chez vous" |
Bonjour chez vous |
|||
x |
Infixé |
Réplication |
13 x 3 |
131313 |
"Salut " x 3 |
Salut Salut Salut |
|||
~~ |
Infixé |
Smart match (reconnaissance intelligente) |
2 ~~ 2 |
True |
2 ~~ Int |
True |
|||
"Perl 6" ~~ "Perl 6" |
True |
|||
"Perl 6" ~~ Str |
True |
|||
"Renaissance" ~~ /naissance/ |
「naissance」 |
|||
++ |
Préfixé |
Incrémentation |
my $var = 2; ++$var; |
Incrémente la variable de 1 et retourne le résultat 3 |
Suffixé |
Incrémentation |
my $var = 2; $var++; |
Retourne la variable 2 et puis l'incrémente |
|
-- |
Préfixé |
Décrémentation |
my $var = 2; --$var; |
Décrémente la variable de 1 et retourne le résultat 1 |
Suffixé |
Décrémentation |
my $var = 2; $var--; |
Retourne la variable 2 et puis la décrémente |
|
+ |
Préfixé |
Force l'opérande à une valeur numérique |
+"3" |
3 |
+True |
1 |
|||
+False |
0 |
|||
- |
Préfixé |
Force l'opérande à une valeur numérique et retourne la négation |
-"3" |
-3 |
-True |
-1 |
|||
-False |
0 |
|||
? |
Préfixé |
Force l'opérande à une valeur booléenne |
?0 |
False |
?9.8 |
True |
|||
?"Hello" |
True |
|||
?"" |
False |
|||
my $var; ?$var; |
False |
|||
my $var = 7; ?$var; |
True |
|||
! |
Préfixé |
Force l'opérande à une valeur booléenne et retourne la négation |
!4 |
False |
.. |
Infixé |
Construction d'intervalles |
0..5 |
Crée un intervalle de 0 à 5 |
..^ |
Infixé |
Construction d'intervalles |
0..^5 |
Crée un intervalle de 0 à 4 |
^.. |
Infixé |
Construction d'intervalles |
0^..5 |
Crée un intervalle de 1 à 5 |
^..^ |
Infixé |
Construction d'intervalles |
0^..^5 |
Crée un intervalle de 1 à 4 |
^ |
Préfixé |
Construction d'intervalles |
^5 |
Comme 0..^5 Crée un intervalle de 0 à 4 |
… |
Infixé |
Construction de listes paresseuses |
0…9999 |
Retourne les éléments seulement si nécessaire |
| |
Préfixé |
Aplanissement |
|(0..5) |
(0 1 2 3 4 5) |
|(0^..^5) |
(1 2 3 4) |
Pour la liste complète des opérateurs, y compris leur priorité : http://doc.perl6.org/language/operators.
3. Variables▲
Les variables sont classées en trois catégories : scalaires, tableaux et hachages.
Un sigil (signe en latin) est un caractère utilisé comme préfixe pour classer les variables.
- $ est utilisé pour les scalaires.
- @ est utilisé pour les tableaux.
- % est utilisé pour les tables de hachage.
3-1. Scalaire▲
Un scalaire contient une valeur ou une référence.
Certaines opérations peuvent être effectuées sur un scalaire, suivant le type de valeur qu'il contient.
Chaîne
my $nom
=
'François Pinon'
;
say
$nom
.uc
;
say
$nom
.chars;
say
$nom
.flip;
ce qui affiche :
FRANÇOIS PINON
14
noniP sioçnarF
Pour une liste exhaustive des méthodes applicables aux chaînes, voir http://doc.perl6.org/type/Str.
Entier
my $age
=
17
;
say
$age
.is-prime
;
Ce qui affiche :
True
Pour une liste exhaustive des méthodes applicables aux entiers, voir http://doc.perl6.org/type/Int.
Nombre rationnel
my $age
=
2
.3
;
say
$age
.numerator;
say
$age
.denominator;
say
$age
.nude;
Ceci affiche :
23
10
(23 10)
Pour une liste exhaustive des méthodes applicables aux nombres rationnels, voir http://doc.perl6.org/type/Rat.
3-2. Tableaux▲
Les tableaux sont des listes contenant plusieurs valeurs. Par défaut, les valeurs d'un tableau peuvent être de différents types.
my @animaux
=
'chameau'
,'lama'
,'hibou'
;
say
@animaux
;
De nombreuses opérations peuvent être effectuées sur les tableaux comme le montre l'exemple suivant :
Le tilde ~ est utilisé pour la concaténation.
my @animaux
=
'chameau'
,'vigogne'
,'lama'
;
say
"Le zoo contient "
~
@animaux
.elems ~
" animaux"
;
say
"Les animaux sont: "
~
@animaux
;
say
"Je vais adopter un hibou pour le zoo"
;
@animaux
.push
("hibou"
);
say
"Maintenant, mon zoo contient: "
~
@animaux
;
say
"Le premier animal que nous avons adopté est le "
~
@animaux
[0
];
@animaux
.pop
;
say
"Malheureusement, le hibou est parti, il ne nous reste que: "
~
@animaux
;
say
"Nous allons fermer le zoo et laisser un animal seulement"
;
say
"Nous allons faire partir: "
~
@animaux
.splice
(1
,2
) ~
" et laisser le "
~
@animaux
;
Le zoo contient 3 animaux
Les animaux sont: chameau vigogne lama
Je vais adopter un hibou pour le zoo
Maintenant, mon zoo contient: chameau vigogne lama hibou
Le premier animal que nous avons adopté est le chameau
Malheureusement, le hibou est parti, il ne nous reste que: chameau vigogne lama
Nous allons fermer le zoo et laisser un animal seulement
Nous allons faire partir: vigogne lama et laisser le chameau
Explication
.elems retourne le nombre d'éléments contenus dans le tableau.
.push() ajoute un élément au tableau.
Nous pouvons accéder à un élément spécifique dans le tableau en spécifiant sa position @animaux[0].
.pop supprime le dernier élément du tableau.
.splice(a,b) supprime les b éléments à partir de la position a.
3-2-1. Tableaux de taille fixe▲
Un tableau simple se déclare comme ceci :
my @tableau
;
Le tableau simple à une taille non définie, et peut varier de façon automatique.
Ce tableau acceptera un nombre illimité de valeurs sans restriction.
On peut en revanche créer des tableaux de taille fixe.
Ces tableaux ne pourront pas excéder la taille qui leur aura été allouée (en lecture et écriture).
Pour déclarer un tableau de taille fixe, spécifiez son nombre maximal d'éléments entre crochets à la suite de son nom :
my @tableau
[3
];
Ce tableau pourra contenir un maximum de trois valeurs, indexées de 0 à 2.
my @tableau
[3
];
@tableau
[0
] =
"première valeur"
;
@tableau
[1
] =
"deuxième valeur"
;
@tableau
[2
] =
"troisième valeur"
;
Vous ne pourrez pas ajouter une quatrième valeur à ce tableau :
my @tableau
[3
];
@tableau
[0
] =
"première valeur"
;
@tableau
[1
] =
"deuxième valeur"
;
@tableau
[2
] =
"troisième valeur"
;
@tableau
[3
] =
"quatrième valeur"
;
Index 3 for dimension 1 out of range (must be 0..2)
3-2-2. Tableaux à plusieurs dimensions▲
Les tableaux vus précédemment ne sont qu'à une dimension.
Heureusement, nous pouvons en Perl 6 déclarer des tableaux de dimensions multiples.
my @multi-tab
[3
;2
];
Ce tableau a deux dimensions. La première dimension peut contenir un maximum de trois valeurs et la seconde un maximum de deux valeurs.
my @multi-tab
[3
;2
];
@multi-tab
[0
;0
] =
1
;
@multi-tab
[0
;1
] =
"x"
;
@multi-tab
[1
;0
] =
2
;
@multi-tab
[1
;1
] =
"y"
;
@multi-tab
[2
;0
] =
3
;
@multi-tab
[2
;1
] =
"z"
;
say
@multi-tab
Pour la référence complète des tableaux : http://doc.perl6.org/type/Array.
3-3. Hachage▲
Un hachage (table de hachage/hash) est un ensemble de paires clef/valeur.
my %capitales
=
('Angleterre'
,'Londres'
,'France'
,'Paris'
);
say
%capitales
;
Une autre façon succincte de remplir le hachage :
my %capitales
=
(Angleterre =>
'Londres'
, France =>
'Paris'
);
say
%capitales
;
Voici quelques-unes des méthodes qui peuvent être appelées sur les hachages :
my %capitales
=
(Angleterre =>
'Londres'
, Allemagne =>
'Berlin'
);
%capitales
.push: (France =>
'Paris'
);
say
%capitales
;
say
%capitales
.kv;
say
%capitales
.keys
;
say
%capitales
.values
;
say
"La capitale de la France est: "
~
%capitales<France>
;
{
Allemagne =>
Berlin, Angleterre =>
Londres, France =>
Paris}
(France Paris Allemagne Berlin Angleterre Londres)
(France Allemagne Angleterre)
(Paris Berlin Londres)
La capitale de la France est: Paris
Explication
.push: (clef => 'valeur') ajoute une nouvelle paire clef/valeur.
.kv renvoie la liste contenant toutes les clefs et valeurs.
.keys renvoie une liste des clefs.
.values renvoie une liste des valeurs.
On peut accéder à la valeur particulière d'un hachage en spécifiant sa clef, comme suit : %hachage<clef>
Pour la référence complète des hachages: http://doc.perl6.org/type/Hash.
3-4. Types▲
Dans les exemples précédents, on n'a pas précisé quel type de valeurs les variables peuvent contenir.
.WHAT retournera le type de la valeur contenue dans la variable.
Comme vous pouvez le voir dans l'exemple ci-dessus, le type de valeur contenu dans $var était (Str) et puis (Int).
Ce style de programmation est appelé le typage dynamique. Dynamique dans le sens que les variables peuvent contenir des valeurs de tout type.
Maintenant, essayez d'exécuter l'exemple ci-dessous :
Remarquez Int avant le nom de la variable.
Il va échouer et retourner ce message d'erreur: Type check failed in assignment to $var; expected Int but got Str.
Ce qui est arrivé est que nous avons précisé au préalable que la variable doit être de type (Int). Quand nous avons essayé de lui affecter un (Str), le programme a échoué.
Ce style de programmation est appelé le typage statique. Statique dans le sens que les types de variables sont définis avant l'affectation et ne peuvent pas changer.
Perl 6 possède un typage graduel, les deux typages, statique et dynamique, peuvent être utilisés.
Voici une liste des types les plus couramment utilisés.
Les deux premiers ne seront probablement jamais utilisés, mais ils sont répertoriés à titre informatif.
Type |
Description |
Exemple |
Résultat |
---|---|---|---|
Mu |
La racine de la hiérarchie de types |
||
Any |
Classe de base par défaut pour les nouvelles classes et pour la plupart des classes intégrées |
||
Cool |
Valeur qui peut être considérée comme une chaîne ou un nombre interchangeable |
my Cool $var = 31; say $var.flip; say $var * 2; |
13 62 |
Str |
Chaîne de caractères |
my Str $var = "NEON"; say $var.flip; |
NOEN |
Int |
Entier (précision arbitraire) |
7 + 7 |
14 |
Rat |
Nombre rationnel (précision limitée) |
0.1 + 0.2 |
0.3 |
Bool |
Booléen |
!True |
False |
3-5. Introspection▲
L'introspection est le processus d'obtention d'informations sur les propriétés d'un objet comme son type.
Dans l'exemple précédent, nous avons utilisé .WHAT pour connaître le type de la variable.
my Int $var
;
say
$var
.WHAT; # (Int)
my $var2
;
say
$var2
.WHAT; # (Any)
$var2
=
1
;
say
$var2
.WHAT; # (Int)
$var2
=
"Hello"
;
say
$var2
.WHAT; # (Str)
$var2
=
True;
say
$var2
.WHAT; # (Bool)
$var2
=
Nil;
say
$var2
.WHAT; # (Any)
Le type d'une variable contenant une valeur est corrélé à sa valeur.
Le type d'une variable vide fortement déclarée est le type avec lequel elle a été déclarée.
Le type d'une variable vide qui n'a pas été déclarée fortement est (Any).
Pour vider la valeur d'une variable, vous pouvez lui affecter Nil.
3-5-1. Portée▲
Avant d'utiliser une variable pour la première fois, elle doit être déclarée.
Plusieurs déclarateurs peuvent être utilisés dans Perl 6, my est ce que nous avons utilisé jusqu'ici.
my $var
=
1
;
Le déclarateur my donne à la variable une portée lexicale. En d'autres termes, la variable ne sera accessible que dans le bloc où elle a été déclarée.
Un bloc en Perl 6 est délimité par { }. Si aucun bloc n'est trouvé, la variable sera disponible dans l'ensemble du script (on dit alors parfois qu'elle est globale au script).
{
my Str $var
=
'Texte'
;
say
$var
; #accessible
}
say
$var
; #inaccessible, renvoie une erreur
Comme une variable est uniquement accessible dans le bloc où elle est définie, le même nom de variable peut être redéfini dans un autre bloc.
3-6. Affecter vs. Lier▲
Nous avons vu dans les exemples précédents comment affecter des valeurs aux variables.
L'affectation est faite en utilisant l'opérateur =
Nous pouvons modifier la valeur attribuée à une variable :
Affecter
123
999
D'autre part, nous ne pouvons pas changer la valeur liée à une variable.
Le lien est établi en utilisant l'opérateur :=
Lier
123
Cannot assign to an immutable value
Une variable peut être également liée à une autre :
Un lien ne peut être créé que lors de l'initialisation de la variable liée, et ne peut plus être modifié ensuite. Mais la valeur de la variable liée peut néanmoins changer si la valeur de la variable « maîtresse » à laquelle elle est liée change.
Pour plus d'informations sur les variables, rendez-vous à http://doc.perl6.org/language/variables.
4. Fonctions normales et fonctions mutatrices▲
Il est important de différencier entre les fonctions normales et les fonctions mutatrices.
Les fonctions normales ne changent pas l'état initial de l'objet.
Les fonctions mutatrices modifient l'état de l'objet.
2.
3.
4.
5.
6.
7.
8.
9.
10.
my @numeros
=
[7
,2
,4
,9
,11
,3
];
@numeros
.push
(99
);
say
@numeros
; #1
say
@numeros
.sort
; #2
say
@numeros
; #3
@numeros
.=
sort
;
say
@numeros
; #4
[7 2 4 9 11 3 99] #1
(2 3 4 7 9 11 99) #2
[7 2 4 9 11 3 99] #3
[2 3 4 7 9 11 99] #4
Explication
.push est une fonction mutatrice, elle change l'état du tableau (#1).
.sort est une fonction normale, elle retourne un tableau trié, mais ne modifie pas l'état initial du tableau :
- (#2) démontre le retour d'un tableau trié ;
- (#3) démontre que le tableau initial reste non modifié.
Afin de forcer une fonction normale à agir comme une fonction mutatrice, nous pouvons utiliser .= a la place de . (#4) (Ligne 9 du script).
5. Structures conditionnelles et boucles▲
Perl 6 possède une multitude de structures conditionnelles et structures de boucles.
5-1. if▲
Le code ne s'exécute que si la condition a été remplie.
En Perl 6, nous pouvons inverser le code et la condition.
Même si le code et la condition ont été inversés, la condition est toujours évaluée en premier.
Si la condition n'est pas remplie, nous pouvons toujours préciser des blocs d'exécution alternatifs en utilisant :
- else
- elsif
5-2. unless▲
La version négative d'un if peut être écrite en utilisant unless.
Le code suivant :
my $chaussures-propres
=
False;
if not
$chaussures-propres
{
say
'Nettoyez vos chaussures'
}
peut aussi être écrit ainsi :
my $chaussures-propres
=
False;
unless $chaussures-propres
{
say
'Nettoyez vos chaussures'
}
La négation en Perl 6 est faite en utilisant ! ou not.
unless (condition) est utilisé à la place de if not (condition).
unless ne peut pas avoir une clause else.
5-3. with▲
with fonctionne comme if, mais vérifie si la variable est définie.
Si vous exécutez le code sans attribuer une valeur à la variable, il ne se passera rien.
without est la version négative de with. Vous devriez être capable de relier le concept à unless.
Si la première condition with n'est pas remplie, un autre chemin peut être spécifié en utilisant orwith.
with et orwith peuvent être comparés à if et elsif.
5-4. for▲
La boucle for itère sur plusieurs valeurs.
Notez que nous avons créé une variable d'itération $element afin d'effectuer l'opération *100 sur chaque élément du tableau. Dans ce genre de construction, la variable d'itération $element est autodéclarée et ne doit donc pas être précédée par le déclarateur my.
5-5. given▲
given est l'équivalent Perl 6 de l'instruction switch dans d'autres langages.
my $var
=
42
;
given $var
{
when 0
..50
{
say
'Plus petit que 50'
}
when Int {
say
"est un Int"
}
when 42
{
say
42
}
default {
say
"heu?"
}
}
Si l'une des conditions est satisfaite, le processus d'appariement s'arrête (les autres conditions ne seront pas testées). Le code ci-dessus n'affichera donc que « Plus petit que 50 ».
Si l'on préfère tester aussi les conditions suivantes, proceed instruira Perl 6 à poursuivre l'appariement, même après un appariement réussi.
5-6. loop▲
loop est une autre façon d'écrire une boucle for.
En fait loop s'écrit comme le sont les boucles for dans les langages de programmation appartenant à la famille C.
Perl 6 appartient à la famille C.
Pour plus d'informations sur les boucles et les conditions, voir http://doc.perl6.org/language/control.
6. Entrées/Sorties▲
En Perl 6, deux des interfaces entrée/sortie les plus communes sont le Terminal et les Fichiers.
6-1. E/S Basic en utilisant le terminal▲
6-1-1. say▲
say écrit sur la sortie standard (en général, l'écran). Il ajoute un caractère de fin ligne à la fin. Autrement dit, le code suivant :
say
'Bonjour Madame.'
;
say
'Bonjour Monsieur.'
;
sera écrit sur deux lignes distinctes.
6-1-2. print▲
print fonctionne comme say, mais sans ajouter de caractère de fin ligne.
Essayez de remplacer say avec print et de comparer les deux résultats.
6-1-2-1. get▲
get est utilisé pour capturer l'entrée du terminal.
my $nom
;
say
"Salut quel est ton nom?"
;
$nom
=
get;
say
"Cher
$nom
bienvenue à Perl 6"
;
Lorsque le code ci-dessus est lancé, le terminal attendra que vous saisissiez votre nom. Par la suite, il vous accueillera.
6-1-3. prompt▲
prompt est une combinaison de print et get.
L'exemple ci-dessus peut être écrit comme ceci :
my $nom
=
prompt("Salut quel est ton nom? "
);
say
"Cher
$nom
bienvenue à Perl 6"
;
6-2. Exécution de commandes Shell▲
Deux routines peuvent être utilisées pour exécuter des commandes shell :
- run : exécute une commande externe sans impliquer le shell ;
- shell : exécute une commande via le shell. Tous les métacaractères sont interprétés par le shell, y compris les tubes (pipes), les redirections, les variables d'environnement, etc.
Voici un exemple sous Linux, Unix ou OS X :
my $nom
=
'Neo'
;
run 'echo'
, "salut
$nom
"
;
shell "ls"
;
Et un exemple sous Windows :
shell "dir"
;
echo et ls sont des mots-clefs communs des shells Unix ou Linux.
echo imprime le texte sur le terminal (l'équivalent de say en Perl 6).
ls liste tous les fichiers et dossiers dans le répertoire courant sous Linux et dir fait la même chose sous Windows.
6-3. E/S Fichier▲
6-3-1. slurp▲
slurp est utilisé pour lire les données d'un fichier.
Créez un fichier texte avec le contenu suivant :
datafile.txt
John 9
Johnnie 7
Jane 8
Joanna 7
my $data
=
slurp "datafile.txt"
;
say
$data
;
6-3-2. spurt▲
spurt est utilisé pour écrire des données sur un fichier.
my $newdata
=
"New scores:
Paul 10
Paulie 9
Paulo 11"
;
spurt "newdatafile.txt"
, $newdata
;
Après avoir exécuté le code ci-dessus, un nouveau fichier nommé newdatafile.txt sera créé. Il contiendra les nouveaux scores.
6-4. Travailler avec les fichiers et répertoires▲
Perl 6 peut lister le contenu d'un répertoire sans exécuter des commandes shell (en utilisant ls) comme nous l'avons vu dans un exemple précédent.
say
dir; #Liste les fichiers et dossiers dans le répertoire courant
say
dir "Documents"
; #Liste les fichiers et dossiers dans le répertoire spécifié
my @répertoire
=
dir; # Récupère les fichiers dans un tableau
De plus, vous pouvez créer de nouveaux dossiers et les supprimer.
mkdir
"newfolder"
;
rmdir
"newfolder"
;
mkdir crée un nouveau répertoire.
rmdir supprime un répertoire vide. Renvoie une erreur s'il n'est pas vide.
Vous pouvez également vérifier si le chemin d'accès spécifié existe, si c'est un fichier ou un répertoire.
Dans le répertoire où vous allez exécuter le script ci-dessous, créez un dossier vide folder123 et un fichier Perl 6 vide script123.pl6
say
"script123.pl6"
.IO.e;
say
"folder123"
.IO.e;
say
"script123.pl6"
.IO.d;
say
"folder123"
.IO.d;
say
"script123.pl6"
.IO.f;
say
"folder123"
.IO.f;
La méthode IO sert à transformer la chaîne de caractères « script123 » en un objet de type IO::Path. Les méthodes « e », « f » et « d » de tests de fichiers ne peuvent être invoquées que sur des objets de type IO::Path, d'où la nécessité de coercition préalable de la chaîne de caractères en un objet de ce type.
IO.e vérifie si le répertoire/fichier existe.
IO.f vérifie si c'est un fichier.
IO.d vérifie si c'est un dossier.
Les utilisateurs Windows peuvent utiliser / ou \\ comme séparateur entre les dossiers :
C:\\rakudo\\bin
C:/rakudo/bin
Pour plus d'informations sur les E/S, voir http://doc.perl6.org/type/IO.
7. Routines▲
7-1. Définition▲
Les routines ou subroutines ou subs sont un moyen de conditionnement d'un ensemble de fonctionnalités.
Une routine est définie avec le mot-clef sub. Après leur définition, elles peuvent être appelées par leur nom.
Examinez l'exemple ci-dessous :
sub salut-
alien {
say
"Bonjour Terriens"
;
}
salut-
alien;
L'exemple précédent présente une routine qui ne nécessite aucun argument.
7-2. Signature▲
Beaucoup de routines requièrent des données en entrée pour fonctionner. Ces données sont fournies par des arguments.
La signature est le nombre et le type d'arguments que la routine accepte.
La routine ci-dessous accepte une chaîne de caractères pour argument :
7-3. Multiroutines▲
Il est possible de définir plusieurs routines ayant le même nom, mais des signatures différentes. Lorsque la routine est appelée, l'environnement d'exécution décidera quelle version utiliser en fonction du nombre et du type des arguments fournis. Ce type de routines est défini de la même manière que les routines normales sauf que nous utilisons le mot-clef multi à la place de sub.
7-4. Arguments optionnels et par défaut▲
Si une routine est définie comme acceptant un argument, et nous l'appelons sans fournir l'argument requis, la routine va échouer.
Cependant, Perl 6 nous offre la possibilité de définir des routines avec des :
- arguments optionnels ;
- arguments par défaut.
Les arguments optionnels sont définis en ajoutant ? après le nom de l'argument.
sub dis-
bonjour($nom
?
) {
with $nom
{
say
"Bonjour "
~
$nom
}
else {
say
"Bonjour être humain"
}
}
dis-
bonjour;
dis-
bonjour("Laura"
);
Si l'utilisateur ne fournit pas un argument, la routine peut fournir une valeur par défaut.
Cela se fait par l'attribution d'une valeur à l'argument durant la définition de la routine.
sub dis-
bonjour($nom
=
"Raoul"
) {
say
"Bonjour "
~
$nom
;
}
dis-
bonjour;
dis-
bonjour("Laura"
);
Pour plus d'informations sur les routines et fonctions, voir http://doc.perl6.org/language/functions.
8. Programmation fonctionnelle▲
Ce chapitre traitera des fonctionnalités facilitant la programmation fonctionnelle.
8-1. Les fonctions sont des entités de première classe▲
Les fonctions/routines sont des entités de première classe :
- elles peuvent être passées comme un argument ;
- elles peuvent être renvoyées par une fonction ;
- on peut les affecter à une variable.
Un bon exemple pour vérifier ce concept est la fonction map.
map est une fonction d'ordre supérieur, elle accepte une autre fonction comme argument.
(1 4 9 16 25)
Explication
Nous avons défini une routine appelée carré, qui met à la puissance 2 l'argument qui lui est passé.
Ensuite, nous avons utilisé map, une fonction d'ordre supérieur en lui passant deux arguments, une routine et un tableau.
Le résultat est une liste de tous les éléments du tableau mis à la puissance 2.
Notez que quand une routine est passée comme argument, nous la préfixons avec &.
8-2. Fermeture▲
Tous les objets code en Perl 6 sont des fermetures, ce qui implique qu'ils peuvent référencer des variables lexicales d'une portée externe.
8-3. Fonctions anonymes▲
Une fonction anonyme est également appelée lambda.
Une fonction anonyme n'est pas liée à un identifiant (elle n'a pas de nom).
Réécrivons l'exemple de map avec une fonction anonyme
my @tableau
=
<
1
2
3
4
5
>
;
say
map
(->
$x
{
$x
**
2
}
,@tableau
);
Notez qu'au lieu de définir une routine et de la passer en argument à map, nous la définissons directement à l'intérieur de map.
La routine anonyme -> $x {$x ** 2} n'a pas de nom et ne peut donc pas être appelée.
En dialecte Perl 6, nous l'appelons un bloc pointu (pointy block).
Un bloc pointu peut aussi être utilisé pour assigner des fonctions à des variables :
my $carré
=
->
$x
{
$x
**
2
}
say
$carré
(9
);
8-4. Enchaînement▲
En Perl 6, les méthodes peuvent être enchaînées, vous n'avez plus à passer le résultat d'une méthode comme argument à une autre.
Supposons qu'on vous donne un tableau de valeurs. On vous demande de retourner les valeurs uniques de ce tableau en ordre décroissant.
Vous pouvez résoudre ce problème en écrivant quelque chose comme ceci :
my @tableau
=
<
7
8
9
0
1
2
4
3
5
6
7
8
9
>
;
my @tableau-final
=
reverse
(sort
(unique
(@tableau
)));
say
@tableau-final
;
Nous appelons d'abord la fonction unique sur @tableau puis nous passons le résultat comme argument à sort et ensuite passons le résultat à reverse.
L'exemple ci-dessus peut aussi être écrit comme suit, en prenant avantage de l'enchaînement des méthodes :
my @tableau
=
<
7
8
9
0
1
2
4
3
5
6
7
8
9
>
;
my @tableau-final
=
@tableau
.unique
.sort
.reverse
;
say
@tableau-final
;
Vous pouvez constater qu'enchaîner les méthodes est plus agréable à l'œil et au cerveau.
8-5. Opérateur feed▲
L'opérateur feed, appelé Pipe dans d'autres langages fonctionnels, donne une meilleure vue de l'enchaînement de méthodes.
Feed vers l'avant
my @tableau
=
<
7
8
9
0
1
2
4
3
5
6
7
8
9
>
;
@tableau
==>
unique
()
==>
sort
()
==>
reverse
()
==>
my @tableau-final
;
say
@tableau-final
;
Explication
commence avec `@tableau` puis renvoie la liste des éléments uniques
puis effectue un tri
puis l'inverse
puis stocke le résultat dans @tableau-final
Comme vous le voyez, le flux des appels de méthodes se fait de haut en bas.
Feed vers l'arrière
my @tableau
=
<
7
8
9
0
1
2
4
3
5
6
7
8
9
>
;
my @tableau-final-v2
<==
reverse
()
<==
sort
()
<==
unique
()
<==
@tableau
;
say
@tableau-final-v2
;
Explication
Le feed vers l'arrière est comme celui vers l'avant, mais se fait à rebours.
Le flux des appels de méthodes se fait de bas en haut.
8-6. Hyperopérateur▲
L'hyperpérateur >>. invoque une méthode sur tous les éléments d'une liste et renvoie une liste des résultats.
my @tableau
=
<
0
1
2
3
4
5
6
7
8
9
10
>
;
sub est-
pair($var
) {
$var
%%
2
}
;
say
@tableau
>>
.is-prime
;
say
@tableau
>>
.&
est-
pair;
En utilisant l'hyperopérateur, nous pouvons appeler des méthodes déjà définies dans Perl 6, par exemple is-prime qui nous indique si un nombre est premier ou pas.
Nous pouvons également définir de nouvelles routines et les appeler en utilisant l'hyperopérateur. En ce cas, il faut préfixer la méthode avec &. Ex. : &est-pair.
Cette façon de faire est très pratique, car elle nous évite d'écrire une boucle for d'itération sur chaque valeur.
8-7. Jonctions▲
Une jonction est une superposition logique des valeurs.
Dans l'exemple ci-dessous, 1|2|3 est une jonction.
L'utilisation de jonctions déclenche généralement l'autothreading ; l'opération est effectuée pour chaque élément de la jonction, les résultats sont combinés en une seule jonction et renvoyés.
8-8. Listes paresseuses▲
Une liste paresseuse est une liste dont l'évaluation peut être retardée.
L'évaluation paresseuse diffère l'évaluation d'une expression jusqu'au moment où celle-ci est nécessaire, et évite ainsi la répétition des évaluations en stockant les résultats dans une table de correspondance.
Les avantages, parmi d'autres, sont les suivants :
- un gain de performance évitant les calculs inutiles ;
- la possibilité de construire des structures de données potentiellement infinies ;
- la possibilité de définir une structure de contrôle.
Pour construire une liste paresseuse, on utilise l'opérateur infixé ...
Une liste paresseuse possède un ou des éléments initiaux, un générateur, et un élément final.
Liste paresseuse simple
my $lazylist
=
(1
... 10
);
say
$lazylist
;
L'élément initial est 1, et l'élément final est 10. Aucun générateur n'a été défini donc le générateur par défaut se fait par succession (+1).
Autrement dit, cette liste paresseuse retournera (à la demande) les éléments suivants : (1, 2, 3, 4, 5, 6, 7, 8, 9, 10).
Liste paresseuse infinie
my $lazylist
=
(1
... Inf);
say
$lazylist
;
Cette liste retournera (à la demande) les entiers entre 1 et l'infini, c'est-à-dire tous les entiers.
Liste paresseuse utilisant un générateur déduit
my $lazylist
=
(0
,2
... 10
);
say
$lazylist
;
Les éléments initiaux sont 0 et 2, et l'élément final est 10. Aucun générateur n'est défini, mais en utilisant les éléments initiaux, Perl 6 déduira que le générateur est (+2).
Cette liste paresseuse retournera (à la demande) les éléments suivants : (0, 2, 4, 6, 8, 10).
Liste paresseuse utilisant un générateur défini
my $lazylist
=
(0
, {
$_
+
3
}
... 12
);
say
$lazylist
;
Dans cet exemple, nous définissons explicitement un générateur mis entre { }
Cette liste paresseuse retournera (à la demande ) les éléments suivants : (0, 3, 6, 9, 12).
Si vous utilisez un générateur explicite, l'élément final doit être une valeur que le générateur puisse retourner.
Si nous reproduisons l'exemple ci-dessus avec un élément final égal à 10 au lieu de 12, il n'y aura pas de fin. Le générateur saute par dessus l'élément final.
Vous pouvez sinon remplacer 0 ... 10 par 0 ...^ * > 10
Ce qui se lit comme : de 0 jusqu'à la première valeur supérieure à 10 exclue.
Ceci ne stoppera pas le générateur
my $lazylist
=
(0
, {
$_
+
3
}
... 10
);
say
$lazylist
;
Ceci stoppera le générateur
my $lazylist
=
(0
, {
$_
+
3
}
...^
*
>
10
);
say
$lazylist
;
9. Classes et Objets▲
9-1. Introduction▲
La Programmation Orientée Objet est l'un des paradigmes les plus utilisés de nos jours.
Un objet est une collection de variables et de routines empaquetées ensemble.
Les variables sont appelées des attributs et les routines des méthodes.
Les attributs définissent l'état et les méthodes le comportement d'un objet.
Une classe définit la structure d'une collection d'objets.
Pour comprendre cette relation, examinez l'exemple ci-dessous :
Il y a 4 personnes présentes dans une pièce |
objets ⇒ 4 personnes |
Ces 4 personnes sont des êtres humains |
classe ⇒ Humain |
Ils ont des noms, âges, sexes et nationalités différents |
attributs ⇒ nom, âge, sexe, nationalité |
Dans le jargon orienté objet, nous disons que les objets sont des instances d'une classe.
Voyez le script ci-dessous :
class Humain {
has $nom
;
has $age
;
has $sexe
;
has $nationalité
;
}
my $françois
;
$françois
=
Humain.new(nom =>
'François'
, age =>
23
, sexe =>
'M'
, nationalité =>
'Sarthoise'
);
say
$françois
;
Le mot-clef class est utilisé pour définir une classe.
Le mot-clef has est utilisé pour définir un attribut d'une classe.
La méthode .new() est appelée un constructeur. Elle crée l'objet comme une instance de la classe sur laquelle elle a été appelée.
Dans le script ci-dessus, la nouvelle variable $françois contient une référence vers une nouvelle instance de « Humain » définie par Humain.new().
Les arguments passés à la méthode .new() sont utilisés pour initialiser les attributs de l'objet.
Une classe peut se voir donner une portée lexicale en utilisant my :
9-2. Encapsulation▲
L'encapsulation est un concept orienté objet qui rassemble une collection de données et de méthodes.
Les données (attributs) dans un objet se doivent d'être privées, c'est-à-dire qu'elles ne sont accessibles qu'à l'intérieur de l'objet.
Pour avoir accès aux attributs depuis l'extérieur de l'objet, on utilise des méthodes appelées accesseurs.
Les deux scripts ci-dessous ont le même résultat.
Accès direct à la variable :
my $var
=
7
;
say
$var
;
Encapsulation :
La méthode disvar est un accesseur. Elle nous permet d'avoir accès à la valeur de la variable sans avoir d'accès direct à celle-ci.
L'encapsulation est facilitée en Perl 6 par l'emploi de twigils.
Les twigils sont des sigils secondaires. Ils s'intercalent entre le sigil et le nom de l'attribut.
On utilise 2 twigils dans les classes :
- ! est utilisé pour déclarer explicitement qu'un attribut est privé ;
- . est utilisé pour générer automatiquement un accesseur pour un attribut.
Par défaut, tous les attributs sont privés, mais c'est une saine habitude que d'utiliser le twigil !.
En accord avec ce qui vient d'être dit, nous devrions réécrire la classe comme suit :
class Humain {
has $!
nom;
has $!
age;
has $!
sexe;
has $!
nationalité;
}
my $françois
=
Humain.new(nom =>
'François'
, age =>
23
, sexe =>
'M'
, nationalité =>
'Sarthoise'
);
say
$françois
;
Si vous ajoutez à ce script la ligne suivante : say $françois.age;
L'erreur suivante sera retournée : Method 'age' not found for invocant of class 'Humain'
La raison en est que $!age est privé et ne peut être utilisé que dans l'objet. Y accéder en dehors de l'objet retournera une erreur.
Maintenant remplacez has $!age par has $.age et voyez quel est le résultat de say $françois.age;
9-3. Arguments nommés vs. positionnels▲
En Perl 6, toutes les classes héritent d'un constructeur par défaut .new().
Il peut être utilisé pour créer des objets en leur fournissant des arguments.
Le constructeur par défaut ne peut se voir fournir que des arguments nommés.
Si vous regardez l'exemple ci-dessus, vous voyez que les arguments passés à .new() sont définis par leur noms :
- nom ⇒ 'François'
- age ⇒ 23
Et si je ne veux pas passer le nom de chaque attribut à chaque fois que je crée un nouvel objet ?
Je dois alors créer un autre constructeur qui accepte les arguments positionnels.
class Humain {
has $.
nom;
has $.
age;
has $.
sexe;
has $.
nationalité;
#nouveau constructeur qui prime sur constructeur par défaut.
method new ($nom
,$age
,$sexe
,$nationalité
) {
self.bless
(:$nom
,:$age
,:$sexe
,:$nationalité
);
}
}
my $françois
=
Humain.new('François'
,23
,'M'
,'Sarthoise'
);
say
$françois
;
Le constructeur qui accepte des arguments positionnels doit être défini comme ci-dessus.
9-4. Méthodes▲
9-4-1. Introduction▲
Les méthodes sont les routines d'un objet.
Comme les routines, elles sont un moyen d'empaqueter une collection de fonctionnalités, elles acceptent des arguments, ont une signature et peuvent être définies comme multi.
Les méthodes sont définies en utilisant le mot-clef method.
Dans leur usage courant, les méthodes sont requises pour effectuer une action sur les attributs des objets. Ce qui applique l'idée d'encapsulation. Les attributs des objets ne peuvent être manipulés qu'à l'intérieur de l'objet en utilisant des méthodes. L'environnement extérieur ne peut interagir avec l'objet qu'à travers ses méthodes, et n'a pas accès à ses attributs.
class Humain {
has $.
nom;
has $.
age;
has $.
sexe;
has $.
nationalité;
has $.
éligible;
method confirme-
éligibilité {
if self.age <
21
{
$!
éligible =
'Non'
}
else {
$!
éligible =
'Oui'
}
}
}
my $françois
=
Humain.new(nom =>
'John'
, age =>
23
, sexe =>
'M'
, nationalité =>
'Sarthoise'
);
$françois
.confirme-
éligibilité;
say
$françois
.éligible;
Une fois les méthodes définies dans une classe, elles peuvent être appelées sur un objet en utilisant l'opérateur point :
objet . méthode ou comme dans l'exemple ci-dessus : $françois.confirme-éligibilité
Dans la définition d'une méthode, si nous avons besoin de faire référence à l'objet en soi pour appeler une autre méthode, on utilise le mot-clef self.
Dans la définition d'une méthode, si nous avons besoin de faire référence à un attribut, on utilise ! même s'il a été défini avec .
La raison en est que le twigil . déclare en fait un attribut privé (avec !) et automatise ensuite la création d'un accesseur ayant le même nom.
Dans l'exemple ci-dessus if self.age < 21 et if $!age < 21 auraient le même résultat, bien qu'ils soient techniquement différents :
- self.age appelle la méthode .age (accesseur).
On peut aussi l'écrire $.age ; - $!age est un appel direct à la variable.
9-4-2. Méthodes privées▲
Les méthodes normales peuvent être appelées sur des objets depuis l'extérieur de la classe.
Les Méthodes privées sont des méthodes qui ne peuvent être appelées qu'à l'intérieur de la classe.
Un cas possible d'usage serait une méthode qui en appelle une autre pour une action spécifique. La méthode qui communique avec l'extérieur est publique alors que celle qui est référencée doit rester privée. Nous ne voulons pas que les utilisateurs l'appellent directement, on la déclare donc comme privée.
La déclaration d'une méthode privée nécessite l'emploi du twigil ! avant son nom.
Les méthodes privées sont appelées avec ! à la place de .
9-5. Attributs de classe▲
Les attributs de classe sont des attributs qui appartiennent à la classe, mais pas à ses objets.
Ils peuvent être initialisés pendant la définition.
Les attributs de classe sont déclarés en utilisant my au lieu de has.
Ils sont appelés sur la classe elle-même au lieu de ses objets.
9-6. Types d'accès▲
Jusqu'à présent, tous les exemples que nous avons vus utilisent des accesseurs pour obtenir des informations sur les attributs de l'objet.
Et si nous avons besoin de modifier la valeur d'un attribut, nous devons marquer cet attribut comme lisible/modifiable en utilisant le mot-clef is rw
class Humain {
has $.
nom;
has $.
age is rw;
}
my $françois
=
Humain.new(nom =>
'François'
, age =>
21
);
say
$françois
.age;
$françois
.age =
23
;
say
$françois
.age;
Par défaut, tous les attributs sont déclarés en lecture seule, mais vous pouvez aussi les déclarer explicitement avec is readonly.
9-7. Hérirage▲
9-7-1. Introduction▲
L'héritage est un autre concept de la programmation orientée objet.
Quand on définit des classes, on se rend compte que ces classes ont certains attributs/méthodes communs.
Devons-nous dupliquer le code ?
NON ! Il faudrait utiliser l'héritage.
Disons que nous voulons créer deux classes, une pour les humains et une pour les employés.
Les humains ont deux attributs : nom et âge.
Les employés ont quatre attributs : nom, âge, société et salaire.
On pourrait être tenté de définir les classes comme suit :
class Humain {
has $.
nom;
has $.
age;
}
class Employé {
has $.
nom;
has $.
age;
has $.
société;
has $.
salaire;
}
Bien que correcte, la part de code ci-dessus est conceptuellement maladroite.
Une meilleure approche serait :
class Humain {
has $.
nom;
has $.
age;
}
class Employé is Humain {
has $.
société;
has $.
salaire;
}
Le mot-clef is définit l'héritage.
Dans le Jargon orienté objet, on dit que Employé est un enfant (ou une classe fille) de Humain, et Humain est un parent d'Employé.
Toutes les classes filles héritent des attributs et des méthodes de la classe parente, il est donc inutile de les redéfinir.
9-7-2. Surcharge▲
Les classes héritent de tous les attributs et méthodes de leur classe parente.
Dans certains cas, nous avons besoin que la méthode d'une classe fille se comporte différemment de celle dont elle hérite.
Afin d'obtenir ce comportement, nous redéfinissons la méthode dans la classe fille.
Ce concept est nommé surcharge. Dans l'exemple ci-dessous, la classe Employé hérite de la méthode présentez-vous.
class Humain {
has $.
nom;
has $.
age;
method présentez-
vous {
say
"Bonjour je suis un être humain, et je m'appelle "
~
self.nom;
}
}
class Employé is Humain {
has $.
société;
has $.
salaire;
}
my $françois
=
Humain.new(nom =>
'François'
, age =>
23
,);
my $anne
=
Employé.new(nom =>
'Anne'
, age =>
25
, société =>
'Acme'
, salaire =>
2000
);
$françois
.présentez-
vous;
$anne
.présentez-
vous;
La surcharge se fait comme ceci :
class Humain {
has $.
nom;
has $.
age;
method présentez-
vous {
say
"Bonjour je suis un être humain, et je m'appelle "
~
self.nom;
}
}
class Employé is Humain {
has $.
société;
has $.
salaire;
method présentez-
vous {
say
"Bonjour je suis un être humain, et je m'appelle "
~
self.nom ~
' et je travaille chez: '
~
self.société;
}
}
my $françois
=
Humain.new(nom =>
'François'
, age =>
23
,);
my $anne
=
Employé.new(nom =>
'Anne'
, age =>
25
, société =>
'Acme'
, salaire =>
2000
);
$françois
.présentez-
vous;
$anne
.présentez-
vous;
Suivant la classe dans laquelle se trouve l'objet, la bonne méthode sera appelée.
9-7-3. Sous-méthodes▲
Les sous-méthodes sont un type de méthode dont les classes filles n'héritent pas.
Elles ne sont accessibles que depuis la classe dans laquelle elles sont déclarées.
Elles sont déclarées en utilisant le mot-clef submethod.
9-8. Héritage multiple▲
L'héritage multiple est disponible en Perl 6. Une classe peut hériter de plusieurs autres classes.
class barre-
graph {
has Int @
.barre-
valeurs;
method dessiner {
say
@
.barre-
valeurs;
}
}
class ligne-
graph {
has Int @
.ligne-
valeurs;
method dessiner {
say
@
.ligne-
valeurs;
}
}
class combo-
graph is barre-
graph is ligne-
graph {
}
my $ventes-réelles
=
barre-
graph.new(barre-
valeurs =>
[10
,9
,11
,8
,7
,10
]);
my $ventes-prévisions
=
ligne-
graph.new(ligne-
valeurs =>
[9
,8
,10
,7
,6
,9
]);
my $réelles-vs-prévisions
=
combo-
graph.new(barre-
valeurs =>
[10
,9
,11
,8
,7
,10
],
ligne-
valeurs =>
[9
,8
,10
,7
,6
,9
]);
say
"Ventes Réelles:"
;
$ventes-réelles
.dessiner;
say
"Ventes Prévisionelles:"
;
$ventes-prévisions
.dessiner;
say
"Réelles vs Prévisionelles:"
;
$réelles-vs-prévisions
.dessiner;
Ventes Réelles:
[10 9 11 8 7 10]
Ventes Prévisionelles:
[9 8 10 7 6 9]
Réelles vs Prévisionelles:
[10 9 11 8 7 10]
Explication
La classe combo-graph doit être capable de contenir deux séries, une pour les valeurs réelles dessinées sous forme de barres et une autre pour les valeurs prévisionnelles dessinées sous forme de ligne.
C'est pourquoi nous l'avons définie comme fille de ligne-graph et barre-graph.
Vous avez remarqué que l'appel de la méthode dessiner sur combo-graph n'a pas rendu les bons résultats.
Une seule série a été dessinée.
Que s'est-il passé ?
combo-graph hérite de barre-graph et de ligne-graph ; et chaque parent possède une méthode appelée dessiner. Quand nous appelons cette méthode sur combo-graph, Perl 6 résoudra le conflit en appelant une des méthodes héritées.
Correction
Pour avoir un comportement valide, nous devons surcharger la méthode dessiner dans combo-graph.
class barre-
graph {
has Int @
.barre-
valeurs;
method dessiner {
say
@
.barre-
valeurs;
}
}
class ligne-
graph {
has Int @
.ligne-
valeurs;
method dessiner {
say
@
.ligne-
valeurs;
}
}
class combo-
graph is barre-
graph is ligne-
graph {
method dessiner {
say
@
.barre-
valeurs;
say
@
.ligne-
valeurs;
}
}
my $ventes-réelles
=
barre-
graph.new(barre-
valeurs =>
[10
,9
,11
,8
,7
,10
]);
my $ventes-prévisions
=
ligne-
graph.new(ligne-
valeurs =>
[9
,8
,10
,7
,6
,9
]);
my $réelles-vs-prévisions
=
combo-
graph.new(barre-
valeurs =>
[10
,9
,11
,8
,7
,10
],
ligne-
valeurs =>
[9
,8
,10
,7
,6
,9
]);
say
"Ventes Réelles:"
;
$ventes-réelles
.dessiner;
say
"Ventes Prévisionelles:"
;
$ventes-prévisions
.dessiner;
say
"Réelles vs Prévisionelles:"
;
$réelles-vs-prévisions
.dessiner;
Ventes Réelles:
[10 9 11 8 7 10]
Ventes Prévisionelles:
[9 8 10 7 6 9]
Réelles vs Prévisionelles:
[10 9 11 8 7 10]
[9 8 10 7 6 9]
9-9. Rôles▲
Les rôles sont assimilables à des classes, dans le sens qu'ils sont une collection d'attributs et de méthodes.
Les rôles sont déclarés avec le mot-clef role, les classes qui veulent implémenter un rôle peuvent le faire en utilisant le mot-clef does.
Réécrivons l'exemple d'héritage multiple en utilisant des rôles :
role barre-
graph {
has Int @
.barre-
valeurs;
method dessiner {
say
@
.barre-
valeurs;
}
}
role ligne-
graph {
has Int @
.ligne-
valeurs;
method dessiner {
say
@
.ligne-
valeurs;
}
}
class combo-
graph does barre-
graph does ligne-
graph {
method dessiner {
say
@
.barre-
valeurs;
say
@
.ligne-
valeurs;
}
}
my $ventes-réelles
=
barre-
graph.new(barre-
valeurs =>
[10
,9
,11
,8
,7
,10
]);
my $ventes-prévisions
=
ligne-
graph.new(ligne-
valeurs =>
[9
,8
,10
,7
,6
,9
]);
my $réelles-vs-prévisions
=
combo-
graph.new(barre-
valeurs =>
[10
,9
,11
,8
,7
,10
],
ligne-
valeurs =>
[9
,8
,10
,7
,6
,9
]);
say
"Ventes Réelles:"
;
$ventes-réelles
.dessiner;
say
"Ventes Prévisionelles:"
;
$ventes-prévisions
.dessiner;
say
"Réelles vs Prévisionelles:"
;
$réelles-vs-prévisions
.dessiner;
Si vous lancez le script ci-dessus, vous constatez que les résultats sont les mêmes.
Vous vous demandez maintenant : si les rôles se comportent comme des classes, quelle est leur utilité ?
Pour répondre à votre question, modifiez le premier script utilisé pour illustrer l'héritage multiple, celui où nous avons oublié de surclasser la méthode dessiner.
role barre-
graph {
has Int @
.barre-
valeurs;
method dessiner {
say
@
.barre-
valeurs;
}
}
role ligne-
graph {
has Int @
.ligne-
valeurs;
method dessiner {
say
@
.ligne-
valeurs;
}
}
class combo-
graph does barre-
graph does ligne-
graph {
}
my $ventes-réelles
=
barre-
graph.new(barre-
valeurs =>
[10
,9
,11
,8
,7
,10
]);
my $ventes-prévisions
=
ligne-
graph.new(ligne-
valeurs =>
[9
,8
,10
,7
,6
,9
]);
my $réelles-vs-prévisions
=
combo-
graph.new(barre-
valeurs =>
[10
,9
,11
,8
,7
,10
],
ligne-
valeurs =>
[9
,8
,10
,7
,6
,9
]);
say
"Ventes Réelles:"
;
$ventes-réelles
.dessiner;
say
"Ventes Prévisionelles:"
;
$ventes-prévisions
.dessiner;
say
"Réelles vs Prévisionelles:"
;
$réelles-vs-prévisions
.dessiner;
===SORRY!===
Method 'dessiner' must be resolved by class combo-graph because it exists in multiple roles (ligne-graph, barre-graph)
Explication
Si plusieurs rôles sont appliqués à la même classe, et un conflit survient, une erreur de compilation sera lancée.
Ceci est une approche plus sûre que l'héritage multiple, où les conflits ne sont pas pris comme des erreurs et sont résolus à l'exécution.
Les rôles vous avertiront en cas de conflit.
9-10. Introspection▲
L'introspection sert à obtenir des informations sur les propriétés d'un objet : comme son type, ses attributs ou ses méthodes.
class Humain {
has $.
nom;
has $.
age;
method présentez-
vous {
say
"Bonjour je suis un être humain, et je m'appelle "
~
self.nom;
}
}
class Employé is Humain {
has $.
société;
has $.
salaire;
}
my $françois
=
Humain.new(nom =>
'François'
, age =>
23
,);
my $anne
=
Employé.new(nom =>
'Anne'
, age =>
25
, société =>
'Acme'
, salaire =>
2000
);
$françois
.présentez-
vous;
$anne
.présentez-
vous;
say
$françois
.WHAT;
say
$anne
.WHAT;
say
$françois
.^
attributes;
say
$anne
.^
attributes;
say
$françois
.^
methods;
say
$anne
.^
methods;
say
$anne
.^
parents;
if $anne
~~
Humain {
say
'anne est un être humain'
}
;
L'introspection est facilitée par :
- .WHAT renvoie la classe depuis laquelle l'objet a été créé ;
- .^attributes renvoie une liste qui contient tous les attributs de l'objet ;
- .^methods renvoie toutes les méthodes invocables de l'objet ;
- .^parents renvoie toutes les classes parentes de la classe à laquelle appartient l'objet ;
- ~~ est appelé l'opérateur de correspondance intelligente (smart-match). Il renvoie Vrai si l'objet correspond à sa classe de création ou à une de celles dont elle a hérité.
10. Gestion des exceptions▲
10-1. Capture des exceptions▲
Les exceptions sont un comportement particulier qui intervient quand quelque chose se passe mal à l'exécution.
On dit que les exceptions sont lancées ou générées.
Le script ci-dessous s'exécute correctement :
Bonjour Josiane
Comment ça va?
Maintenant, voici un script analogue qui lance une exception :
Type check failed in assignment to $nom; expected Str but got Int (123)
Vous remarquerez que quand une erreur survient (ici affecter un nombre à une variable de chaîne), le programme s'arrête et les lignes suivantes ne seront pas évaluées, même si elles sont correctes.
La gestion des exceptions capture une exception qui a été lancée afin que le script puisse continuer à fonctionner.
my Str $nom
;
try {
$nom
=
123
;
say
"Hello "
~
$nom
;
CATCH {
default {
say
"Pouvez vous nous redonner votre nom, nous ne l'avons pas trouvé dans le registre."
;
}
}
}
say
"Comment ça va?"
;
Pouvez vous nous redonner votre nom, nous ne l'avons pas trouvé dans le registre.
Comment ça va?
La gestion d'exception se fait en utilisant un bloc try-CATCH.
try {
#le code va ici
#si quelque chose se passe mal le script entre dans le bloc CATCH
#si tout se passe bien, le bloc CATCH sera ignoré
CATCH {
default {
#le code présent ici ne sera évalué que si une exception a été lancée
}
}
}
Un bloc CATCH peut se définir de la même façon qu'un bloc given. Ce qui implique qu'on puisse faire un catch sur différents types d'exceptions.
try {
#le code va ici
#si quelque chose se passe mal le script entre dans le bloc CATCH
#si tout se passe bien, le bloc CATCH sera ignoré
CATCH {
when X::AdHoc {
#faire quelque chose si une exception de type X::AdHoc est lancée }
when X::IO {
#faire quelque chose si une exception de type X::IO est lancée }
when X::OS {
#faire quelque chose si une exception de type X::OS est lancée }
default {
#faire quelque chose si une exception est lancée qui ne correspond pas aux types précédents }
}
}
10-2. Lancer des exceptions▲
À l'inverse de capturer les exceptions, Perl 6 vous permet aussi d'en lancer.
On peut lancer deux types d'exceptions :
- les exceptions ad hoc ;
- les exceptions typées.
Les exceptions ad hoc sont lancées en utilisant la routine die suivie du message de l'exception.
Les exceptions typées sont des objets, d'où l'utilisation du constructeur .new() dans l'exemple ci-dessus.
Toutes les exceptions descendent de la classe X, quelques exemples ci-dessous :
X::AdHoc est le type le plus simple d'exception ;
X::IO est lié aux erreurs IO (entrées/sorties) ;
X::OS est lié aux erreurs OS (système) ;
X::Str::Numeric est lié aux erreurs de conversion d'une chaîne vers un nombre.
Pour une liste complète des types d'exceptions et une liste de leurs méthodes associées, allez sur http://doc.perl6.org/type.html et naviguez dans les types qui commencent par X.
11. Expressions régulières▲
Une expression régulière, ou regex est une séquence de caractères utilisée pour le filtrage par motif.
La méthode la plus simple pour concevoir ce système est d'y penser comme un motif qui peut être répété/isolé/extrait.
if 'ensoleillement'
~~
m/ soleil /
{
say
"ensoleillement contient le mot soleil"
;
}
Dans cet exemple l'opérateur de correspondance intelligent (smart-match) ~~ est utilisé pour vérifier si une chaîne de caractères (ensoleillement) contient le mot (soleil).
« ensoleillement » est comparé à la regex m/ soleil /.
11-1. Définition d'une regex▲
Une expression régulière peut être définie comme suit :
- /soleil/
- m/soleil/
- rx/soleil/
Les espaces, sauf si spécifiés comme requis explicitement, ne sont pas pris en compte : m/soleil/ and m/ soleil / sont identiques.
11-2. Correspondance par caractères▲
Les caractères alphanumériques et le tiret bas _ sont utilisés tels quels.
Tous les autres caractères doivent être « protégés » en les préfixant de la barre oblique inversée, ou mis entre guillemets (simples ou doubles).
if 'Température: 13'
~~
m/
\:
/
{
say
"La chaîne fournie contient le caractère deux-points :"
;
}
if 'Age = 13'
~~
m/ '=' /
{
say
"La chaîne fournie contient le caractère égal = "
;
}
if 'nom@société.com'
~~
m/ "@" /
{
say
"Cette adresse mail semble valide car elle contient un caractère
@
"
;
}
11-3. Comparaison par catégories de caractères▲
Les caractères peuvent être réunis en catégories de reconnaissances. On peut également utiliser la négation d'une catégorie (tout sauf cette catégorie) :
Catégorie |
Regex |
Inverse |
Regex |
---|---|---|---|
Caractère de mot (lettre, chiffre, ou tiret bas) |
\w |
Tout caractère sauf caractère de mot |
\W |
Chiffre |
\d |
Tout caractère sauf un chiffre |
\D |
Espace |
\s |
Tout caractère sauf espace |
\S |
Espace horizontal |
\h |
Tout caractère sauf espace horizontal |
\H |
Espace vertical |
\v |
Tout caractère sauf espace vertical |
\V |
Tabulation |
\t |
Tout caractère sauf tabulation |
\T |
Saut de ligne |
\n |
Tout caractère sauf saut de ligne |
\N |
if "Robert123"
~~
/
\d
/
{
say
"Pas de comparaison valide car pas de chiffres"
;
}
else {
say
"Comparaison valide, car un chiffre"
}
if "John-Doe"
~~
/
\s
/
{
say
"Cette chaîne contient un espace"
;
}
else {
say
"Cette chaîne ne contient pas d'espace"
}
11-3-1. Propriétés unicode▲
La section précédente montre l'utilité d'utiliser des catégories de caractères.
Ceci dit, une approche plus systématique pourrait être d'utiliser les propriétés Unicode.
Les propriétés Unicode sont notées à l'intérieur de <: >
if "Robert123"
~~
/ <:N> /
{
say
"Contient un chiffre"
;
}
else {
say
"Ne contient pas un chiffre"
}
if "Albert-Ebasque"
~~
/ <:Lu> /
{
say
"Contient une lettre en majuscule"
;
}
else {
say
"Ne contient de lettre en majuscule"
}
if "Albert-Ebasque"
~~
/ <:Pd> /
{
say
"Contient un tiret"
;
}
else {
say
"Ne contient pas un tiret"
}
11-3-2. Métacaractères▲
Les métacaractères (wildcards) peuvent également être utilisés dans les regex.
Le point . signifie n'importe quel caractère unique.
11-3-3. Quantificateurs▲
Les quantificateurs viennent après un caractère et sont utilisés pour déterminer le nombre de fois qu'il doit apparaître.
Le point d'interrogation ? signifie zéro ou une fois.
if 'ac'
~~
m/ a?c /
{
say
"Correspondance"
;
}
else {
say
"Pas de Correspondance"
;
}
if 'c'
~~
m/ a?c /
{
say
"Correspondance"
;
}
else {
say
"Pas de Correspondance"
;
}
L'astérisque * signifie zéro ou plusieurs fois.
if 'az'
~~
m/ a*z /
{
say
"Correspondance"
;
}
else {
say
"Pas de Correspondance"
;
}
if 'aaz'
~~
m/ a*z /
{
say
"Correspondance"
;
}
else {
say
"Pas de Correspondance"
;
}
if 'aaaaaaaaaaz'
~~
m/ a*z /
{
say
"Correspondance"
;
}
else {
say
"Pas de Correspondance"
;
}
if 'z'
~~
m/ a*z /
{
say
"Correspondance"
;
}
else {
say
"Pas de Correspondance"
;
}
Le + signifie au moins une fois.
if 'az'
~~
m/ a+z /
{
say
"Correspondance"
;
}
else {
say
"Pas de Correspondance"
;
}
if 'aaz'
~~
m/ a+z /
{
say
"Correspondance"
;
}
else {
say
"Pas de Correspondance"
;
}
if 'aaaaaaaaaaz'
~~
m/ a+z /
{
say
"Correspondance"
;
}
else {
say
"Pas de Correspondance"
;
}
if 'z'
~~
m/ a+z /
{
say
"Correspondance"
;
}
else {
say
"Pas de Correspondance"
;
}
11-4. Résultats de correspondance▲
Quand la mise en correspondance avec une regex est positive, le résultat est stocké dans la variable spéciale $/
if 'Rakudo est un compilateur Perl 6'
~~
m/compilateur/
{
say
"La correspondance est: "
~
$/
;
say
"La chaîne avant la correspondance est: "
~
$/
.prematch;
say
"La chaîne après la correspondance est: "
~
$/
.postmatch;
say
"La chaîne reconnue commence à la position: "
~
$/
.from;
say
"La chaîne reconnue finit à la position: "
~
$/
.to;
}
La correspondance est: compilateur
La chaîne avant la correspondance est: Rakudo est un
La chaîne après la correspondance est: Perl 6
La chaîne reconnue commence à la position: 14
La chaîne reconnue finit à la position: 25
Explication
$/ renvoie un Objet de Correspondance (Match Object), c'est-à-dire la chaîne qui correspond à la regex
Les méthodes suivantes peuvent être appelées sur le l'Objet de Correspondance :
.prematch renvoie la chaîne qui précède la correspondance ;
.postmatch renvoie la chaîne qui suit la correspondance ;
.from renvoie la position de départ de la correspondance ;
.to renvoie la position de fin de la correspondance.
Par défaut le caractère espace n'est pas pris en compte.
Si nous voulons faire une correspondance avec une regex contenant un espace, nous devons le définir explicitement.
Le :s dans la regex m/:s Perl 6/ force l'espace à être considéré et non ignoré.
D'une autre façon, nous aurions pu écrire la regex comme ceci: m/ Perl\s6/ en utilisant comme vu précédemment \s comme indicateur d'un espace.
Si une regex contient plusieurs espaces, utiliser :s devient plus efficace que l'utilisation de \s pour chaque espace.
11-5. Exemple▲
Vérifions si une adresse mail est valide ou non.
Pour la pertinence de cet exemple, nous conviendrons qu'une adresse mail est valide si elle est formée comme suit :
prénom [point] nom [arobase] société [point] (com/org/net).
La regex utilisée ici pour la validation de mail est très insuffisante. Elle ne sert ici qu'à titre d'exemple pour demontrer les fonctionnalités de regex de Perl 6.
Ne pas l'utiliser telle quelle en production.
my $email
=
'sam.suffit@perl6.org'
;
my $regex
=
/ <:L>+
\.
<:L>+
\@
<:L+:N>+
\.
<:L>+ /
;
if $email
~~
$regex
{
say
$/
~
" est une adresse mail valide"
;
}
else {
say
"n'est pas une adresse mail valide"
;
}
sam.suffit@perl6.org est une adresse mail valide
Explication
<:L> correspond à une lettre.
<:L>+ correspond à une lettre ou plus.
\. correspond à un caractère [point].
\@ correspond à un caractère [arobase].
<:L+:N> correspond à une lettre ou un chiffre.
<:L+:N>+ correspond à une lettre ou un chiffre, plusieurs fois.
La regex peut être décomposée comme suit :
- nom <:L>+
- [point] \.
- prénom <:L>+
- [arobase] \@
- nom de la société <:L+:N>+
- [point] \.
- com/org/net <:L>+
D'une autre façon, une regex peut être divisée en plusieurs regex nommées :
my $email
=
'sam.suffit@perl6.org'
;
my regex lettres {
<:L>+
};
my regex point {
\.
};
my regex arobase {
\@
};
my regex lettres-
et-
chiffres {
<:L+:N>+
};
if $email
~~
/
<lettres>
<point>
<lettres>
<arobase>
<lettres-et-chiffres>
<point>
<lettres>
/
{
say
$/
~
" est une adresse mail valide"
;
}
else {
say
"Ce n'est pas une adresse mail valide"
;
}
Une regex nommée est définie en utilisant la syntaxe suivante : my regex nom-de-la-regex {définition de la regex }
Une regex nommée peut être appelée en utilisant la syntaxe suivante : <nom-de-la-regex>
Pour plus de détails sur les regex, voir http://doc.perl6.org/language/regexes.
12. Modules Perl 6▲
Perl 6 est un langage à but générique. Il peut être utilisé pour remplir plusieurs tâches, incluant : traitement d'un texte, image, web, bases de données, protocoles réseau, etc.
La réutilisabilité est un concept très important qui permet aux programmeurs de ne pas réinventer la roue à chaque nouvelle tâche.
Perl 6 permet la création et la redistribution de modules. Chaque module donne une série de fonctionnalités empaquetées qui, une fois installées, peuvent être réutilisées.
Panda est un outil de gestion de modules livré avec Rakudo.
Pour installer un module spécifique, taper la commande suivante dans votre terminal :
panda install "nom du module"
Une liste des modules Perl 6 se trouve ici: http://modules.perl6.org/.
12-1. Utiliser les modules▲
MD5 est une fonction de hachage cryptographique qui produit une valeur de hachage de 128 bits.
MD5 a de nombreuses utilités, dont le chiffrage des mots de passe stockés dans une base de données. Quand un nouvel utilisateur s'inscrit, ses références ne sont pas stockées en texte brut, mais sous forme de hachage. L'idée derrière tout ceci est que si la base de données est compromise, l'attaquant ne pourra pas identifier les mots de passe.
Disons que vous ayez besoin d'un script qui génère un hachage MD5 sur un mot de passe avant stockage dans la base de données.
Heureusement, Perl 6 possède un module qui implémente l'algorithme de hachage MD5. Installons-le :
panda install Digest::MD5
Maintenant, lançons le script suivant :
use Digest::MD5;
my $secret
=
"secret123"
;
my $secret-h
=
Digest::MD5.new.md5_hex($secret
);
say
$secret-h
;
Pour lancer la fonction md5_hex() qui crée les hachages, nous devons charger le module voulu.
Le mot-clef use charge le module pour son utilisation dans le script.
Dans la pratique, le hachage MD5 n'est pas suffisant, car vulnérable aux attaques par dictionnaire.
Il doit être combiné avec un « salage » https://fr.wikipedia.org/wiki/Salage_(cryptographie).
13. Unicode▲
Unicode est un standard informatique de représentation du texte, qui prend en compte la plupart des systèmes d'écriture dans le monde.
UTF-8 est un encodage de caractères capable d'encoder tous les caractères (ou « Points de code ») en Unicode.
Les caractères sont définis par un :
graphème : représentation visuelle ;
point de code : un nombre assigné à un caractère.
13-1. Utiliser Unicode▲
Voyons comment nous pouvons générer des caractères en utilisant Unicode.
say
"a"
;
say
"
\x00
61"
;
say
"
\c[LATIN SMALL LETTER A]
"
;
Les trois lignes ci-dessus montrent les différentes façons de construire un caractère :
- Écriture directe (graphème) ;
- Utilisation de \x suivi du point de code ;
- Utilisation de \c et du nom du point de code.
Générons maintenant une émoticône (un smiley ).
say
"☺"
;
say
"
\x26
3a"
;
say
"
\c[WHITE SMILING FACE]
"
;
Un autre exemple en combinant deux points de code :
say
"á"
;
say
"
\x00
e1"
;
say
"
\x00
61
\x03
01"
;
say
"
\c[LATIN SMALL LETTER A WITH ACUTE]
"
;
La lettre á peut être écrite :
- en utilisant son point de code unique \x00e1 ;
- ou comme la combinaison des points de code de : a et de l'accent aigu \x0061\x0301.
Quelques méthodes qui peuvent être utilisées :
say
"á"
.NFC;
say
"á"
.NFD;
say
"á"
.uniname;
NFC:0x<00e1>
NFD:0x<0061 0301>
LATIN SMALL LETTER A WITH ACUTE
NFC renvoie le point code unique.
NFD décompose le caractère et renvoie ses points de code.
uniname renvoie le nom du point de code.
Des caractères Unicode peuvent être utilisés en tant qu'identifiants :
my $
Δ =
1
;
$
Δ++
;
say
$
Δ;
14. Parallélisme, concurrence et asynchronisme▲
14-1. Parallélisme▲
En temps normal, toutes les tâches d'un programme s'effectuent de façon séquentielle. Ce n'est pas un grand problème si le temps d'exécution n'est pas crucial pour vous.
Perl 6 intègre de façon naturelle le lancement de tâches en parallèle.
À ce point, il est important de considérer que le parallélisme peut vouloir dire deux choses :
- parallélisme des tâches : deux (ou plus) expressions indépendantes lancées en parallèle ;
- parallélisme des données : une expression unique itérée sur une liste d'éléments en parallèle.
Commençons par ce dernier.
14-1-1. Parallélisme des données▲
my @tableau
=
(0
..50000
); #Remplissage du tableau
my @résultat
=
@tableau
.map
({
is-prime
$_
}
); #Appel de is-prime sur chaque élément
say
now -
INIT now; #Temps d'exécution du programme
Au regard de l'exemple ci-dessus :
nous ne faisons qu'une seule opération @array.map({ is-prime $_ }).
La sous-routine is-prime est appelée séquentiellement pour chaque élément du tableau :
is-prime @tableau[0] puis is-prime @tableau[1] puis is-prime @tableau[2] etc.
Nous pouvons heureusement appeler is-prime sur plusieurs éléments en même temps :
my @tableau
=
(0
..50000
); #Remplissage du tableau
my @résultat
=
@tableau
.race.map
({
is-prime
$_
}
); #Appel de is-prime sur chaque élément
say
now -
INIT now; #Temps d'exécution du programme
Notez l'emploi de race dans l'expression. Cette méthode permet l'itération en parallèle des éléments du tableau.
Après avoir lancé les deux exemples (avec et sans race), comparez les temps d'exécution de chaque programme.
race ne préservera pas l'ordre des éléments. Pour le préserver, utilisez à sa place hyper.
my @tableau
=
(1
..1000
);
my @résultat
=
@tableau
.race.map
( {
$_
+
1
}
);
@résultat
>>
.say
;
my @tableau
=
(1
..1000
);
my @résultat
=
@tableau
.hyper.map
( {
$_
+
1
}
);
@résultat
>>
.say
;
En lançant les deux exemples, vous remarquerez que l'un est trié et l'autre non.
14-1-2. Parallélisme des tâches▲
my @tab1
=
(0
..49999
);
my @tab2
=
(2
..50001
);
my @résultat1
=
@tab1
.map
( {
is-prime
($_
+
1
)}
);
my @résultat2
=
@tab2
.map
( {
is-prime
($_
-
1
)}
);
say
@résultat1
eqv @résultat2
;
say
now -
INIT now;
Voyons l'exemple ci-dessus :
- Nous avons défini deux tableaux ;
- Appliqué une opération itérative différente à chaque tableau, puis stocké les résultats ;
- Ensuite vérifié l'égalité des deux tableaux.
Le script attend que @tab1.map( {is-prime($_ + 1)} ) finisse puis évalue @tab2.map( {is-prime($_ - 1)} ).
Les opérations effectuées sur chaque tableau ne dépendent pas l'une de l'autre.
Pourquoi ne pas les effectuer en parallèle ?
my @tab1
=
(0
..49999
);
my @tab2
=
(2
..50001
);
my $promesse1
=
start @tab1
.map
( {
is-prime
($_
+
1
)}
).eager;
my $promesse2
=
start @tab2
.map
( {
is-prime
($_
-
1
)}
).eager;
my @résultat1
=
await $promesse1
;
my @résultat2
=
await $promesse2
;
say
@résultat1
eqv @résultat2
;
say
now -
INIT now;
Explication
La méthode start évalue le code et renvoie un objet de type promesse, ou plus brièvement une promesse (promise).
Si le code est évalué correctement, la promesse sera tenue (kept).
Si le code lance une exception, la promesse sera non tenue ou rompue (broken).
La méthode await s'attend à une promesse.
Si elle est tenue, elle obtiendra les valeurs renvoyées.
Si elle n'est pas tenue, une exception sera lancée.
Vérifiez le temps pris par chacun des scripts.
Le parallélisme ajoute toujours un surcoût lié à la gestion des processus en parallèle. Si cette surcharge n'est pas compensée par un gain dans le temps de calcul, le script paraîtra plus lent.
C'est pourquoi utiliser race, hyper, start et await avec des scripts assez simples peut effectivement les ralentir.
14-2. Concurrence et asynchronisme▲
Pour plus de détails sur la concurrence et la programmation asynchrone, voir http://doc.perl6.org/language/concurrency.
15. La communauté▲
On discute beaucoup sur le canal IRC #perl6. C'est la bonne porte d'entrée pour toutes vos questions :
http://perl6.org/community/irc
Pour des nouvelles ponctuelles basées sur Perl 6 :
http://pl6anet.org/ est un agrégateur de blogs sur le sujet.
16. Remerciements Developpez▲
Nous remercions Naoum Hankache de nous avoir aimablement autorisés à publier cette Introduction à Perl 6, dont le texte original Perl 6 Introduction peut être trouvé sur http://perl6intro.com/ et une version française sur http://fr.perl6intro.com.
Nous remercions aussi Romuald Nuguet et Stéphane Payrard pour leur participation à la traduction, Djibril, Laurent Rosenfeld et chrtophe pour la mise en forme et la relecture technique ainsi que ClaudeLELOUP pour sa relecture orthographique.
Les commentaires et les suggestions d'amélioration sont les bienvenus. Aussi, après votre lecture, n'hésitez pas : 6 commentaires !