Perl 6 est un nouveau langage de programmation propre, moderne et multiparadigme : il offre des possibilités de programmation procédurale, orientée objet et fonctionnelle ; il ne vous impose aucun de ces modèles de programmation, c'est vous qui choisissez selon vos besoins spécifiques et vos préférences personnelles. Il propose aussi au choix un typage statique fort ou un typage dynamique.
Après une longue période de gestation, la première version stable « de production » du nouveau langage Perl 6 a été officiellement annoncée en décembre 2015 et est disponible au téléchargement. La distribution stable complète s'appelle Rakudo Star et contient Rakudo Perl 6, le compilateur Perl 6, la machine virtuelle MoarVM, une suite de modules additionnels et une abondante documentation. Cette distribution est disponible pour les environnements Linux, Mac OS X et Windows (voir encadré).
Perl 6 est une nouvelle mouture du langage Perl, qui reste dans l'esprit des versions antérieures de Perl (« fais ce que je veux », « il y a plus d'une façon de le faire », etc.), mais les concepteurs de Perl 6 ont décidé de rompre avec la tradition de compatibilité ascendante de la syntaxe remontant à plus de 25 ans, ce qui a permis un toilettage assez important de la syntaxe et ouvert des possibilités réellement nouvelles et radicalement modernes.
Installer et utiliser Rakudo / Perl 6
À l'heure où nous écrivons, les paquets proposés par les grandes distributions Linux proposent des versions trop anciennes. Vérifiez pour votre propre distribution, mais, par exemple, Debian propose un paquet « stable » datant de 2014 et un paquet de test de novembre 2015. Idéalement, il faudrait au moins la version 2016.01 de Rakudo-Star pour avoir la version stable de production de Perl 6. On peut imaginer que la situation va évoluer et que des paquets de la version de production seront disponibles dans les semaines ou les mois qui viennent pour diverses distributions de Linux, mais il est aujourd’hui préférable de télécharger le fichier tar à l'adresse http://rakudo.org/downloads/star/ et de l'installer soi-même. Par exemple :
$ wget http://rakudo.org/downloads/star/rakudo-star-2016.01.tar.gz
$ tar xzf rakudo-star-2016.01.tar.gz
$ cd rakudo-star-2016.01
$ perl Configure.pl --backend=moar --gen-moar
$ make
$ make rakudo-test
$ make rakudo-spectest
$ make install
Des informations complémentaires peuvent être trouvées sur le site de Rakudo : http://rakudo.org/how-to-get-rakudo/.
Une fois l'installation effectuée, vous voudrez sans doute mettre à jour votre PATH dans le fichier ~/.bashrc puis sourcer ce fichier. Ensuite, en tapant perl6 -v à la ligne de commande, vous devriez avoir quelque chose du genre :
$ perl6 -v
This is Rakudo version 2016.01.1 built on MoarVM version 2016.01
implementing Perl 6.c.
En tapant perl6 à l'invite du shell, on entre dans la boucle REPL (read, evaluate, print loop) qui affiche une invite de ligne de commande permettant de tester des instructions ou expressions Perl 6 simples.
> say "Hello World!";
Hello World!
Pour exécuter un script, tapez simplement perl6 suivi du nom du programme :
perl6 script.pl6
La documentation officielle (en anglais) sur Perl 6 est disponible à l'adresse suivante : doc.perl6.org.
Plusieurs articles et tutoriels en français sont en ligne à l'adresse suivante : http://perl.developpez.com/cours/#TutorielsPerl6.
1. Une brève introduction à Perl 6
Prenez un langage de programmation généraliste quelconque et affichez le résultat de la simple opération arithmétique suivante : 0.3 - 0.2 - 0.1. Il y a toutes les chances que vous obteniez un résultat tel que -2.77555756156289e-17 (en Perl 5), -2.775558e-17 (en C sous gcc) ou -2.7755575615628914e-17 (en Java, Python 3, Ruby ou TCL). Ce dernier résultat paraît peut-être plus précis (plus de décimales), mais il se trouve en fait être légèrement plus loin de la vérité, puisque ce total devrait normalement être égal à 0. Ces résultats erronés ne sont pas dûs à une faiblesse des langages en question, mais au fait que nos ordinateurs ne sont pas très bons en arithmétique avec des nombres fractionnaires.
Essayons avec la boucle REPL de Perl 6 :
> my $l'addition-devrait-être-zéro = .3 - .2 - .1;
0
> say sprintf "%.50f", $l'addition-devrait-être-zéro;
0.00000000000000000000000000000000000000000000000000
On voit que Perl 6 affiche la valeur correcte (0), même quand on demande d'afficher les 50 premières décimales. Ce résultat est correct parce qu'en interne, Perl 6 stocke des nombres décimaux dans un type Rat (rationnel), sous la forme d'un couple numérateur / dénominateur, et peut donc obtenir une précision arbitraire... et surtout un résultat correct. On peut même comparer le résultat à 0 :
> say "Vrai" if $l'addition-devrait-être-zéro == 0;
Vrai
Tout développeur un tant soit peu expérimenté sait qu'il ne faut surtout pas faire ce genre de comparaison dans la plupart des langages de programmation. En Perl 6, ça marche parfaitement. Cet exemple montre la mise en pratique du principe « Do What I Mean » (DWIM) cher aux concepteurs du langage Perl 6 : on s'attend normalement à ce que cette opération soit égale à 0, mais on constate que ce n'est pas le cas dans la plupart des langages de programmation. Perl 6 « fait exactement ce que nous voulons dire ». Ce simple problème d'addition est un premier exemple de ce qu'un langage radicalement moderne devrait faire : sauf peut-être si nous développons des microcodes pour une puce embarquée, nous ne devrions plus, en 2016, avoir à nous demander si notre ordinateur sait compter correctement, ce devrait être acquis depuis longtemps. Avec Perl 6, votre ordinateur sait enfin le faire.
L'exemple ci-dessus illustre au passage quelques autres caractéristiques de Perl 6. Comme en Perl 5 (et en PHP), les noms de variables commencent par un caractère spécial, nommé sigil, ici le signe $ pour une variable scalaire, suivi de l'identifiant proprement dit, qui doit commencer par un caractère alphabétique ou le caractère de soulignement _. Elles doivent être déclarées avant d'être utilisées, ici avec le mot-clef my. Perl 6 supporte pleinement l'Unicode, et les identifiants de variables ou de fonctions peuvent contenir des lettres françaises accentuées (ci-dessus, le « ê » et le « é »), mais on aurait aussi bien pu utiliser des lettres grecques :
> my $φ = (5**.5 + 1)/2; # nombre d'or
1.61803398874989
> say "Le nombre d'or est égal à $φ.";
Le nombre d'or est égal à 1.61803398874989.
> my $π = 4 * atan 1;
3.14159265358979;
On aurait également pu utiliser les lettres d'un quelconque autre alphabet. Là encore, la modernité... De plus, comme on le voit dans le premier exemple de code, ces identifiants peuvent également contenir des tirets (« - ») ou des apostrophes (« ' »), à condition qu'ils soient situés entre deux lettres.
On constatera également dans les exemples ci-dessus que Perl 6 n'a généralement pas besoin de beaucoup de parenthèses, sauf quand c'est nécessaire pour des raisons de précédence des opérateurs (comme dans la formule du nombre d'or). Par exemple, les arguments d'une fonction interne peuvent généralement être placés sans parenthèses après le nom de la fonction appelée (et séparés par des virgules s'il y en a plusieurs). De même, on peut souvent enchaîner plusieurs fonctions comme dans l'exemple say sprintf … ci-dessus, Perl 6 sait très bien prendre la ou les valeurs de retour d'une fonction et la ou les passer en argument à la fonction placée à sa gauche. Cela rend la syntaxe souvent plus fluide et plus limpide.
Le caractère # introduit un commentaire s'étendant jusqu'à la fin de la ligne. Il existe d'autres formes de commentaires pouvant être placés au milieu d'une ligne de code ou pouvant couvrir plusieurs lignes, par exemple :
say #`(Commentaire au milieu d'une ligne de code) "Hello World !"; # imprime Hello World !
say #`[Ceci est
un commentaire
multiligne] "Hello World !"; # idem
Mais nous n'entrerons pas plus dans les détails ici.
2. Les variables
2.1 Les diverses sortes de variables
Il existe trois principales sortes de variables, qui se distinguent par le sigil précédant l'identifiant proprement dit :
- le sigil $ indique une variable scalaire, c'est-à-dire une variable ne contenant qu'une seule valeur (par exemple une valeur numérique, une chaîne de caractères, un objet ou une référence vers une autre entité) ;
- le sigil @ désigne une variable de tableau, c'est-à-dire une liste de valeurs indexées par des entiers ;
- le sigil % dénote une table de hachage, qui est définie comme un ensemble de paires clef-valeur.
On accède aux éléments d'un tableau avec l'opérateur [...] et à ceux d'un hachage avec {...}. Contrairement à Perl 5, une variable de tableau ou de hachage conserve son sigil d'origine quand on accède à ses éléments individuels :
> my @tableau = 1, 2, 4, 6;
[1 2 4 6]
> say @tableau[2];
4
> my %hachage = jan => 1, fév => 2, mar => 3;
fév => 2, jan => 1, mar => 3
> say %hachage{"fév"};
2
2.2 Portée des variables
Nous avons vu que le mot-clef my sert à déclarer une variable. Plus précisément, il introduit une variable lexicale, c'est-à-dire une variable dont la portée est limitée au bloc de code dans lequel elle se trouve. Un bloc de code est, en simplifiant un peu, un fragment de code délimité par des accolades ouvrantes et fermantes servant à structurer le code. Une variable lexicale est visible et utilisable entre l'endroit où elle est déclarée avec le my et l'accolade fermant le bloc où se trouve la déclaration. Si la déclaration a lieu à l'extérieur de tout bloc, alors la variable est globale au script (ce qui n'est généralement pas conseillé).
{
my Str $var = "texte";
say $var; # affiche "texte"
}
say $var; # ERREUR: $var n'est plus accessible
On peut aussi avoir deux variables de même nom ayant des valeurs différentes selon la portée dans laquelle elles se trouvent :
my Int var = 42;
{
my Str $var = "texte";
say $var; # affiche "texte"
}
say $var; # -> 42
Ces exemples sont un peu artificiels à ce stade, mais cette possibilité s'avérera très utile quand nous utiliserons des blocs décrivant des boucles ou le corps de fonctions.
2.3 Les types de données
Une variable peut être déclarée avec un type imposant des contraintes sur ses valeurs possibles :
my Int $c;
$c = 4; # tout va bien, $c vaut 4
say $c.WHAT # (Int)
$c = 4.2; # ERREUR : Type check failed in assignment to $c...
Mais la déclaration n'est pas nécessaire et Perl 6 détermine lui-même le type de la donnée dans la mesure du possible :
my $d = 4.2; # Pourrait aussi s'écrire : my $d = Rat.new(42, 10);
say $d.WHAT; # (Rat)
say '$d = ', $d.numerator, " / ",
$d.denominator; # affiche : $d = 21 / 5
On dit que Perl 6 est typé de façon « graduelle » : il autorise aussi bien un typage statique (comme C ou Java) qu'un typage dynamique (comme Perl 5, Ruby ou Python). Le meilleur de deux mondes, en quelque sorte. En fait, les variables $c et $d ci-dessus sont assimilables à des objets, respectivement de type Int et Rat, ce qui explique la possibilité d'invoquer sur eux les méthodes .WHAT ou .numerator. Pour les types les plus courants, il n'est souvent pas nécessaire d'invoquer le constructeur .new pour les obtenir. Ainsi, il existe plusieurs façons de créer des objets de type complexe :
my $z1 = 5 + 3i;
say $z1.WHAT; # (Complex)
my $z2 = Complex.new(4, 9); # 4+9i
my Complex $z3 = 2 + 5i;
say $z1 + $z2 + $z3; # affiche : 11+17i
L'utilisation d'une simple affectation est suffisante pour créer un objet du type voulu, mais les deux syntaxes utilisant explicitement le type Complex sont un peu plus sûres, car elles vérifient le type du littéral affecté à la variable. De même, considérons des objets de type Date :
my $d = Date.new(2015, 12, 24); # Veille de Noël : 2015-12-24
say $d.year; # 2015
say $d.month; # 12
say $d.day; # 24
say $d.day-of-week; # 4 (donc, jeudi)
my $n = Date.new('2015-12-31'); # Saint-Sylvestre
say $n > $d; # False
say $n - $d; # 7 (delta 7 jours)
say $n + 1; # 2016-01-01
say 1+$n.later(:2months); # 2016-03-01
Remarquez au passage combien la manipulation des dates devient facile et intuitive. C'est cela aussi la modernité de Perl 6. Ici, la syntaxe utilisant le constructeur new était nécessaire parce que sans elle, le programme ne pourrait reconnaître une date et effectuerait simplement une double soustraction entre entiers :
> my $d = 2015-12-25; # Non, ce n'est pas Noël
1978
2.4 Les variables scalaires
Les variables scalaires, introduites par le sigil $, ne contiennent qu'un seul élément (mais cet élément peut lui-même être composite, par exemple si c'est un objet comme nous venons de le voir dans les exemples ci-dessus). Les variables scalaires contiennent souvent des chaînes de caractères ou des nombres.
2.4.1 Chaînes de caractères
Les chaînes de caractères sont des séquences immuables de caractères quelconques. Elles sont généralement encadrées par des guillemets ou des apostrophes. La différence est que les variables (et les séquences d'échappement) sont interpolées dans une chaîne de caractères entre guillemets, mais pas dans celles entre apostrophes.
my $user = 'Laurent';
say "Bonjour, $user !"; # Bonjour Laurent !
say 'Bonjour, $user !'; # Bonjour $user !
Le tilde « ~ » est l'opérateur de concaténation de chaînes :
say "Hello" ~ "World !"; # Hello World !
Il existe de nombreuses fonctions ou méthodes travaillant sur des chaînes :
my $nom = "Charlie";
say flip $nom; # eilrahC (syntaxe fonctionnelle)
say $nom.flip; # eilrahC (syntaxe de méthode)
say uc $nom; # CHARLIE
say $nom.uc; # idem
say $nom.chars; # 7 (nombre de caractères)
say substr $nom, 2, 3; # arl (sous-chaîne)
say "Je suis " ~ $nom; # Je suis Charlie (concaténation)
On remarque que les sous-routines internes de Perl 6 admettent pour la plupart une syntaxe de fonction et une syntaxe de méthode. Il est possible de les combiner à volonté, notamment pour clarifier l'intention ou la précédence :
> say flip "Charlie".substr(2, 3).uc
LRA
2.4.2 Données numériques
Nous avons déjà vu des exemples de données numériques de types Int (entier) ou Rat (rationnel). La racine carrée de 2, le logarithme de 5 ou 1017 sont de type Num :
say 2.sqrt.WHAT; # (Num)
say 5.log.WHAT; # (Num)
say 1e17.WHAT; # (Num)
De nombreuses fonctions ou méthodes permettent de travailler sur les données numériques ou seulement sur certains types numériques :
say 19.is-prime; # True (19 est premier)
say 4.7.nude; # (47 10), c-à-d 47/10
Cela n'est pas spécifique aux variables numériques, mais notons au passage qu'il est possible de définir dynamiquement des « sous-types » ou sous-ensembles de types existants. On peut par exemple créer un type nombre impair :
subset Impair of Int where { $_ % 2 } # non divisibles par 2
# Impair est maintenant un sous-type
my Impair $x = 3; # OK
my Impair $y = 2; # erreur de type
2.5 Les tableaux
Les tableaux sont des listes contenant des valeurs multiples. Les valeurs n'ont pas besoin d'être du même type (on peut par exemple mélanger des chaînes et des nombres), mais c'est souvent une bonne idée qu'elles le soient dans la mesure où les éléments d'un tableau doivent en principe avoir une certaine cohérence sémantique. On accède aux valeurs individuelles d'un tableau à l'aide d'indices qui sont des nombres entiers, le premier élément d'un tableau portant l'indice 0.
my @nombres_shadoks = ['GA', 'BU', 'ZO', 'MEU'];
say @nombres_shadoks[1]; # imprime: BU
Si les éléments d'un tableau sont des chaînes de caractères sans espace, on peut utiliser un opérateur de citation de liste <...> pour écrire plus simplement, sans guillemets, apostrophes, ni virgules :
> my @nombres_shadoks = <GA BU ZO MEU>;
[GA BU ZO MEU]
> say @nombres_shadoks.elems; # nombre d'éléments
4
> my $dernier = pop @nombres_shadoks;
MEU
> say @nombres_shadoks;
[GA BU ZO]
> say elems @nombres_shadoks; # nombre d'éléments
3
> say "Les shadoks ont perdu leur dernier chiffre: $dernier";
Les shadoks ont perdu leur dernier chiffre: MEU
> push @nombres_shadoks, $dernier;
[GA BU ZO MEU]
La fonction pop retire le dernier élément du tableau et le renvoie ; la fonction push ajoute un (ou plusieurs) élément(s) à la fin d'un tableau. On aurait aussi pu utiliser une syntaxe de méthode :
> my $dernier = @nombres_shadoks.pop
MEU
> say @nombres_shadoks
[GA BU ZO]
> @nombres_shadoks.push($dernier);
[GA BU ZO MEU]
La fonction splice(a, n) retire n élément(s) d'un tableau à partir de la position a et les renvoie:
> my @nombres_shadoks = <GA BU ZO MEU>;
[GA BU ZO MEU]
> my @elem_1_2 = splice @nombres_shadoks, 1, 2;
[BU ZO]
Mais si l'on désire récupérer collectivement plusieurs éléments d'un tableau sans modifier le tableau, on peut utiliser une syntaxe de tranches de tableaux :
my @nombres_shadoks = <GA BU ZO MEU>;
say @nombres_shadoks[0..2]; # (GA BU ZO)
Il existe de nombreuses autres fonctions ou méthodes utilisables, fournies notamment par les classes internes Array et List de Perl.
Les tableaux peuvent être multidimensionnels. On peut accéder aux éléments d'un tableau multidimensionnel en séparant les indices par un « ; » :
my $prem-rang_deux-col = @tableau[0;1];
2.6 Les hachages
Un hachage est un ensemble de paires clef-valeur. L'idée générale est la même que celle des dictionnaires ou maps dans d'autres langages.
> my %capitales = ("Italie", "Rome", "Allemagne", "Berlin", "Espagne", "Madrid");
Allemagne => Berlin, Espagne => Madrid, Italie => Rome
On peut rendre le code plus concis avec une syntaxe de liste :
> my %capitales = <Italie Rome Allemagne Berlin Espagne Madrid>;
Allemagne => Berlin, Espagne => Madrid, Italie => Rome
Et on peut le rendre plus clair en utilisant la « virgule grasse » => dès l'initialisation :
my %capitales = (Italie => "Rome", Allemagne => "Berlin", Espagne => "Madrid");
La « virgule grasse » => a essentiellement le même rôle qu'une virgule, mais elle rend l'intention plus claire et dispense de mettre la clef entre guillemets.
On peut ajouter un nouvel élément au hachage par une affectation avec une nouvelle clef :
%capitales{"France"} = "Paris";
Ou :
%capitales<France> = "Paris";
La méthode push permet également d'ajouter une nouvelle paire au hachage :
push %capitales, (Danemark => "Copenhague");
%capitales.push: (USA => "Washington");
say %capitales.elems ; # 6 (nombre de paires)
Les méthodes kv, keys et values renvoient respectivement des listes de paires, de clefs et de valeurs :
> say %capitales.kv
(France Paris Allemagne Berlin Italie Rome USA Washington Danemark Copenhague Espagne Madrid)
> say %capitales.keys;
(France Allemagne Italie USA Danemark Espagne)
> say %capitales.values;
(Paris Berlin Rome Washington Copenhague Madrid)
Notons qu'un hachage stocke et restitue les paires dans un ordre apparemment aléatoire (indépendant de celui dans lequel elles ont été créées), mais les trois méthodes renvoient les éléments dans un ordre consistant.
3. Les opérateurs
Perl 6 possède la plupart des opérateurs communs aux langages de programmation usuels et de nombreux autres.
3.1 Principaux opérateurs
Le tableau ci-dessous résume les opérateurs les plus communs, par ordre de précédence descendante (de la priorité la plus forte à la plus faible) :
.method | Méthode post-fixée |
++ -- | Auto-incrémentation, auto-décrémentation (préfixées ou post-fixées) |
** | Exponentielle |
! + - ~ ? | || | Symboles unaires : négation logique, plus, moins, concaténation, coercition booléenne, ou logique |
* / % %% div gcd lcm | Multiplication, division, modulo, divisibilité, division entière, PGDC, PPMC |
+ - | Addition, soustraction |
x xx | Réplication de chaîne (renvoie une chaîne), réplication d'élément (renvoie une liste) |
~ | Concaténation de chaînes |
~~ != == < <= > >= eq ne lt le gt ge | Opérateur de comparaison intelligente, opérateurs de comparaisons numériques, opérateurs de comparaisons de chaînes |
&& | ET booléen (de haute précédence) |
|| | OU booléen (de haute précédence) |
?? !! | Opérateur conditionnel ternaire |
= => += -= **= xx= .= | Opérateurs d'affectation |
so not | Booléens unaires de basse précédence : coercition booléenne et non logique |
and andthen | ET booléen (de basse précédence) |
or xor orelse | OU booléen (de basse précédence) |
Nous verrons plus loin qu'il est facile de construire ses propres opérateurs.
3.2 On en a rêvé, Perl 6 le fait
Les opérateurs de comparaison logique peuvent être chaînés comme en arithmétique, ce qui peut simplifier notablement l'écriture :
say "Valeurs dans l'ordre" if $u < $v < $x < $y < $z;
# équivaut à : ... if $u < $v and $v < $x and $x < $y ...
# ou à : ... if ($u < $v) and ($v < $x) and ...
De même, les jonctions permettent d'écrire des comparaisons concises de ce style :
my $x = 7;
say "Trouvé" if $x == 4|6|9|7|15; # -> Trouvé
# Peut aussi s'écrire :
say "Trouvé" if $x if 7 == any <4 6 9 7 15>;
# équivaut à : ... if ($x == 4) or ($x == 6) or ...
3.3 Les métaopérateurs et hyperopérateurs
Les opérateurs travaillent sur des données, les métaopérateurs travaillent sur des opérateurs et permettent en quelque sorte de créer de nouveaux opérateurs.
Le métaopérateur de réduction [...] permet de transformer un opérateur infixé associatif en un opérateur de liste renvoyant un scalaire :
> say [+] 1, 2, 3, 4;
10
Ici, tout se passe comme si on avait placé l'opérateur + entre chaque élément de la liste, comme si on avait écrit :
> say 1 + 2 + 3 + 4;
10
On peut de même calculer très facilement la factorielle de 10 en modifiant l'opérateur de multiplication :
my $fact10 = [*] 1..10; # -> 3628800
Il existe d'autres métaopérateurs. Par exemple, le métaopérateur X renvoie un produit cartésien entre deux ou plusieurs listes :
> <a b c> X 1, 2;
((a 1) (a 2) (b 1) (b 2) (c 1) (c 2))
Un hyperopérateur applique une opération à chaque membre d'une liste ou de plusieurs listes et renvoie une nouvelle liste. Ici, chaque élément de la liste est multiplié par 5 :
> my @a = 6..10;
[6 7 8 9 10]
> say 5 «*» @a;
[30 35 40 45 50]
À noter que cet hyperopérateur utilise en principe les guillemets français «...», mais vous pouvez utiliser les chevrons ASCII <<...>> si votre éditeur ne vous permet pas d'écrire facilement ces guillemets français.
Avec deux ou plusieurs listes, l'hyperopérateur permet d'effectuer des opérations membre à membre sur les listes. Voici par exemple une concaténation membre à membre entre trois listes :
> my @x = ('a'..'e') «~» (3..7) «~» ('v'..'z');
[a3v b4w c5x d6y e7z]
Les métaopérateurs et hyperopérateurs créent de nouveaux opérateurs en modifiant la sémantique d'opérateurs existants. Nous verrons dans un prochain article qu'il est possible de créer facilement des opérateurs entièrement nouveaux. Tout cela tend à rendre le langage intrinsèquement malléable et extensible.
Conclusion
Ce bref tour d'horizon initial a permis de faire connaissance avec les principaux types de données de Perl 6 et d'apprendre quelques-unes des principales caractéristiques de sa syntaxe. Perl 6 est un langage propre, typé, concis, puissant et expressif. Il est également résolument moderne et offre des fonctionnalités souvent uniques et à la pointe du progrès dans le domaine des langages de programmation.
Le prochain article complétera ce tour d'horizon en passant notamment en revue les structures de contrôle, les fonctions et la création dynamique de nouveaux opérateurs. Là encore, le lecteur pourra constater que non seulement ce langage est innovant et généralement en avance sur ce qui existe ailleurs, mais qu'il est aussi extensible presque à volonté et donc éminemment susceptible de rester à l'avenir en avance sur son temps.