Aller au contenu

Raku (langage)

Un article de Wikipédia, l'encyclopédie libre.
(Redirigé depuis Perl 6)

Raku
Logo.

Date de première version Spécification : 2001-présent, mise en œuvre par Rakudo Star, première version stable annoncée le 25 décembre 2015[1]
Paradigmes Objet, impératif, fonctionnel, dynamique
Auteur Larry Wall
Développeurs The Perl Foundation
Dernière version Rakudo Star 6.d Diwali/
Typage Fort, dynamique et/ou statique, graduel
Influencé par Haskell
Perl
Common Lisp
Ada
META II (en)
APL
Ruby
Python
Smalltalk
SelfVoir et modifier les données sur Wikidata
A influencé Perl, Haskell
Implémentations Pugs, Rakudo (initialement via Parrot, actuellement avec MoarVM et JVM)
Écrit en RakuVoir et modifier les données sur Wikidata
Système d'exploitation Multi-plate-forme
Licence Artistic License 2.0[3]Voir et modifier les données sur Wikidata
Site web https://raku.org/
Extension de fichier raku, rakumod, rakudoc, rakutest et tVoir et modifier les données sur Wikidata

Raku (anciennement Perl 6) est un langage de programmation qui fut un temps considéré comme la sixième version majeure de Perl. Il s'agissait alors d'une refonte profonde du langage, aussi bien dans sa conception que dans son implémentation, rompant avec l'exigence de rétrocompatibilité qui avait primé pour les versions majeures précédentes, bien qu'un mode de compatibilité avec les versions antérieures soit prévu dans les spécifications.

Le nom Raku[4] a été choisi comme « nom de scène » par Larry Wall en réponses aux protestations émanant des partisans de Perl 5, qui souhaitaient que le projet abandonne l'appellation Perl afin de ne pas donner l'impression que Perl 5 était destiné à être remplacé.

Si Raku n'est donc plus considéré comme une nouvelle version de Perl, il garde tout de même l'esprit du langage qui laisse une grande liberté au programmeur et lui permet une expression concise. Raku reste un langage générique et permet toujours de programmer des unilignes, mais il facilite aussi l'écriture de programmes importants, grâce à des fonctionnalités telles que le typage statique des données et un meilleur support de la programmation orientée objet.

Contrairement à Perl, Raku n'est pas défini par une implémentation de référence, mais par des spécifications en langage naturel, ainsi que par un ensemble de codes test[5], dont la rédaction a commencé en avril 2001[6]. Ces spécifications sont publiques et par conséquent tout développeur est libre de créer son implémentation. Raku ne dispose donc pas d'une implémentation unique. Historiquement, au moins trois projets ont tenté d'implémenter le langage ou un sous-ensemble de celui-ci. En 2018, seul Rakudo fait l'objet d'un développement actif.

La Fondation Perl détient le copyright sur l'implémentation Rakudo, qui cible les machines virtuelles JVM et MoarVM[7]. MoarVM est une machine virtuelle spécifiquement écrite pour Rakudo. Rakudo est lui-même en grande partie écrit en Raku.

Le 28 novembre 2015, les équipes de développement de Raku / Rakudo ont annoncé que la distribution 2015.11 de novembre 2015 constituait une version bêta utilisable et stable de Raku[8].

Pendant plusieurs années une remarque humoristique perdurait concernant la sortie de Raku au sein de la communauté Perl. À la question « Quand le langage Perl 6 sera-t-il disponible ? » (le nom « Perl 6 » était de vigueur avant le nommage), la réponse habituelle était « à Noël », mais sans préciser l'année. En 2015, c'est-à-dire après quinze ans d'attente, la version dite « de Noël » est finalement annoncée[9],[10].

Larry Wall et Camelia le logo de Perl6 lors du FOSDEM 2015

Le logo de Raku est appelé Camelia[11]. C'est un papillon, sur les ailes duquel on peut lire la lettre P et le chiffre 6 (le logo date d'avant le renommage en Raku).

Motivations et philosophie

[modifier | modifier le code]

Le langage Perl était au départ très modeste et a grossi en respectant la rétrocompatibilité. Créé en 1987, Perl a accumulé beaucoup de scories qui rendent son apprentissage difficile et complexifient inutilement l'interpréteur. Il fallait s'en débarrasser. Les comportements par défaut du langage étaient conçus pour des programmes de quelques lignes. Même si le langage avait évolué (variables lexicales, orientation objet…) pour supporter de gros programmes, une grande partie des programmeurs n'avaient pas adapté leur style, ce qui a donné à Perl une réputation de langage sale.

L'interpréteur de Perl 5 n'utilise pas au mieux les architectures multiprocesseurs ou multi cœur dont la mémoire est lente par rapport au processeur. De plus, pour la programmation en grand, il est nécessaire d'avoir un système puissant de passage de paramètres. De même, il était important de donner la possibilité au programmeur, mais non l'obligation, d'un typage statique des données. Ce typage constitue à la fois une documentation, une forme d'assertion exécutée à la compilation et une amélioration des performances par rapport au typage dynamique.

Le langage permet toujours d'écrire des programmes très concis, notamment grâce aux compositeurs et aux hyperopérateurs. Ces derniers sont similaires aux opérateurs de manipulation de tableaux dynamiques du langage APL. C'est un des aspects de la syntaxe concrète qui permet de paralléliser l'exécution de portions de programmes.

Le langage est très complet et donc assez complexe, mais il est toujours possible de programmer dans un sous-ensemble restreint du langage. Il inclut beaucoup de fonctionnalités qui, pour d'autres langages, appartiennent généralement à des bibliothèques logicielles. Ainsi le système d'expressions rationnelles a été entièrement refondu et étendu au point de servir de base à de véritables grammaires complètes et de constituer aussi un moteur d'analyse syntaxique puissant et rapide grâce à un contrôle très fin du retour sur trace. Le compilateur Raku actuel se fonde sur une grammaire de Raku écrite en Raku.

Raku est complètement intégré au système objet.

Le système objet, minimaliste en Perl 5, supporte maintenant le dispatch multiple, les rôles[12] et la réflexion via un Protocole à méta-objets inspiré de CLOS.

La programmation orientée prototype et la programmation orientée objet sont toutes deux possibles, car le programmeur peut modifier le comportement par défaut des métaclasses et du mécanisme de dispatch vers les méthodes et multiméthodes. Les rôles sont un système de composition de code similaire aux mixin mais de granularité inférieure à la classe.

Les concepteurs de Raku ont apporté un soin tout particulier à la syntaxe du langage qui avait été notablement alourdie en Perl 5 avec l'ajout du support des références. Les principes directeurs dans la conception du langage sont : le principe de Huffman, la lisibilité, l'extensibilité. Chaque aspect du langage est hautement paramétrable via des constructions lexicales ou syntaxiques appelées adverbes ou modificateurs. Certains opérateurs sont des caractères Unicode mais souvent un alias plus verbeux en ASCII est disponible.

Le typage explicite du contenu d'une variable est optionnel. Le typage des données est donc statique lorsqu'il est explicite ou inféré, dynamique sinon.
Le programmeur dispose donc d'un continuum graduel entre la programmation lâche typique des langages de script et la rectitude et les performances d'un langage à typage statique. Typiquement, un programme évoluera au cours du temps vers un typage plus « serré ».

Bien que les mises en œuvre actuelles de Raku soient à l'heure actuelle moins rapides que Perl 5, le langage devrait à terme être un langage rapide, car, outre le typage statique, le support de la parallélisation, ses implémentations supportent la compilation à la volée en code natif.

Le processus de conception de Raku a été annoncé pour la première fois le 19 juillet 2000, par Larry Wall le 4e jour de la conférence annuelle OSCON dans son discours sur l'état de l’oignon 2000 (« State of the Onion 2000 »). À cette date, les principaux objectifs étaient de débarrasser le langage de verrues historiques (historical warts) et de nettoyer d'une manière générale la conception interne et les API. Le tout était alors résumé par la phrase : « les choses faciles doivent rester faciles, les choses difficiles doivent être plus faciles, et les choses impossibles ne devraient pas être difficiles ».

Le processus a commencé avec une série de demandes de changements ou « RFC » (par analogie aux Request for comments d'internet). Ce processus était ouvert à tous les contributeurs et ne laissait aucun aspect du langage à l’abri du changement. Alors que Larry Wall s'attendait à recevoir une vingtaine de RFC, 361 demandes de changements furent émises par les membres de la communauté Perl.

Une fois le processus des RFC terminé, Wall a revu et classé chaque demande. Il a alors commencé la rédaction de ce qu'il a alors appelé les Apocalypses. Bien que le but initial était d’écrire une Apocalypse pour chaque chapitre du manuel de référence en Perl intitulé « Programmation en Perl », il est devenu évident à la rédaction de chacune des Apocalypses que les précédentes Apocalypses devenaient en partie invalides de par les derniers changements. Pour cette raison, un ensemble de Synopsis ont été publiés, chacun relatif au contenu d’une Apocalypse, mais mis à jour suivant les modifications apparues. Aujourd’hui, les spécifications de Raku continuent presque entièrement à travers les Synopsis.

Au fil des ans, Raku a connu plusieurs changements de direction. L’introduction de concepts provenant de Python et Ruby ont influé au début, mais lors de l’écriture de l’interpréteur Pugs dans le langage Haskell, on a pu noter une large influence de la programmation fonctionnelle sur l’équipe de conception de Raku. Pugs a cependant permis de valider un bon nombre de concepts ou au contraire d'en affiner d'autres.

Pugs est historiquement la première mise en œuvre expérimentale de Raku. Pugs peut exécuter du code Raku directement, ainsi que compiler du Raku vers du JavaScript, du Perl 5 ou du bytecode Parrot. Écrit essentiellement par Audrey Tang, maintenant peu active, Pugs n'est plus développé activement. Il a cependant permis de valider avec une implémentation partielle réelle les principaux concepts et d'en affiner quelques autres.

Actuellement, la seule implémention est Rakudo Star (ou Rakudo *) qui inclut le compilateur Rakudo Perl qui inclut une bibliothèque standard, plus une sélection de bibliothèque tierce partie . Cette version a d'abord été fondée sur la machine virtuelle Parrot, mais se fonde maintenant sur les machines virtuelles MoarVM et JVM.

Rakudo est une implémentation utilisant au départ la machine virtuelle Parrot, et visant à terme l'auto-hébergement de Raku. Parce qu'il est lui-même essentiellement écrit en Raku, Rakudo est susceptible d'être porté relativement facilement vers d'autres machines virtuelles. Le portage vers la Machine virtuelle Java a commencé en 2013, ainsi que vers MoarVM, une machine virtuelle conçue spécialement pour faire tourner Rakudo. La communauté Perl n'a pas forcément la main-d’œuvre pour maintenir une machine virtuelle moderne avec des optimisations dynamiques de code telles que celles fournies par CrankShaft de V8, il est donc probable que d'autres machines virtuelles lui succéderont.

Rakudo, dont le copyright est détenu par la fondation Perl, sera très probablement la première mise en œuvre substantielle de Raku. Pour le bootstrap de Raku, Rakudo utilise NQP (Not Quite Perl), un sous-ensemble de Raku qui comporte le moteur d'analyse syntaxique.

Une distribution spéciale de Rakudo, appelée Rakudo Star, incluant divers modules afin de la rendre « utile et utilisable »[13] est publiée mensuellement depuis juillet 2006[14].

C'est cette distribution Rakudo Star, fondée sur la machine virtuelle MoarVM et disposant en janvier 2017 de plus de 760 modules.

Changements incompatibles

[modifier | modifier le code]

Raku est la première version majeure de Perl qui n'est pas rétrocompatible avec les versions précédentes. Cela signifie qu'un code écrit en Perl 5 échouera probablement à la compilation ou à l'exécution si on tente de l'exécuter ou de le compiler sans modifications comme s'il s'agissait de code Raku (sauf à utiliser le mode de compatibilité prévu dans la spécification et au moins partiellement implanté dans les mises en œuvre actuelles, ce mode permet notamment d'utiliser une bonne partie des modules Perl 5 en Raku).

Les changements incompatibles sont nombreux, mais les plus notables sont l'invariance du sigil, les simplifications syntaxiques et le passage d'arguments.

Invariance du sigil

[modifier | modifier le code]

En Perl 5, le sigil — le caractère non alphanumérique qui précède un nom de variable — pouvait changer selon son contexte d'utilisation (scalaire ou tableau) :

 # Perl 5 code
 my @array = (0, 1, 2, 3);
 my $element = $array[1]; # $element est égal à 1

En Raku, l'abondance des contextes possibles nécessite un mécanisme différent des sigils. Le sigil ne désigne plus le contexte d'accès. Raku propose des opérateurs spécialisés pour ce faire. Le sigil d'une variable est donc invariant. Il est plus pédagogique d'avoir deux mécanismes syntaxiques pour deux fonctions grammaticales différentes (le typage faible de la variable et son contexte d'accès).

 # Code Raku
 my @array = 0, 1, 2, 3;
 my $element = @array[1]; # $element est égal à 1

Passage de paramètres

[modifier | modifier le code]

Les versions antérieures de Perl définissent les sous-routines sans liste formelle de paramètres[15].

Les arguments de sous-routines entrant dans une sous-routine devenaient des alias dans les éléments du tableau @_. Si @_ était modifié, les changements étaient reflétés dans les données originales :

 # Code Perl 5
 sub incr { $_[0]++ }
 my $x = 1;
 incr($x); # $x est maintenant 2
 incr(3); # erreur lors de l'exécution : "Essai de modification d'une valeur en lecture seule"

Même en tenant compte de l'invariance du sigil, la plupart des déclarations de fonctions en Perl 5 échoueront si on cherche à les exécuter comme du code Raku, car Raku utilise un système très différent de passage de paramètres, grâce à un formalisme dans le langage qui va au-delà des signatures de types. En Raku, une déclaration de sous-routine ressemble à :

 sub faire-quelquechose(Str $chose, Int $autre) {  }

Comme en Perl 5, les paramètres formels (exemple, les pseudovariables dans la liste de paramètres) sont aliassés en leurs paramètres effectifs (valeurs d'entrées), mais par défaut, les alias sont marqués is readonly signifiant qu'ils sont en lecture seule et donc constants :

 sub incr(Num $x) {
   $x++; # compile-time error
 }

Si un paramètre formel est suivi par is copy ou is rw, cependant, il peut être modifié. Dans le cas is copy, Raku copie les paramètres actuels plutôt que de les aliasser ; ainsi ils peuvent être modifiés, mais les changements restent locaux à la sous-routine. Dans le cas is rw (rw signifie lecture-écriture, read-write en anglais), l'alias n'est pas marqué readonly. Ce changement détecte aussi, lors de la compilation, des erreurs telles que :

sub incr(Num $x is rw) { $x++ }
incr(3); # erreur au moment de la compilation
sub incr-copy(Num $x is copy) { $x++ }
incr-copy(3); # Pas de problème

De nouvelles fonctionnalités de Raku dans les listes de paramètres rendent le passage de paramètres beaucoup plus puissant qu'en Perl 5 :

  • = après un paramètre permet d'assigner des valeurs par défaut ;
  • ? après un paramètre indique des arguments optionnels ;
  • : avant un paramètre indique un argument nommé (passé comme élément de hachage) ;
  • where peut fournir une condition que le paramètre doit respecter.

Par exemple :

 sub mysplit(Rule $pat? = rx/\s+/, Str $expr? = $_, Int $lim? where $^lim >= 0) {  }

Raku supporte aussi la curryfication.

Simplification syntaxique

[modifier | modifier le code]

Les changements de syntaxe entre Perl 5 et Raku sont nombreux et parfois subtils. Par exemple, une règle fondamentale en Raku est l'interdiction absolue d'avoir deux termes consécutifs. C'est pourquoi la syntaxe d'une fonction telle que map fait désormais apparaître une virgule. Ainsi un code Perl 5 tel que :

# Perl5
print $_ for map { $_**2 } 1 .. 3;

échouera à la compilation si on cherche à l'exécuter comme du code Raku. Il faudra ajouter une virgule entre la fonction anonyme et la liste :

# Raku
say $_ for map { $_**2 }, 1 .. 3;

Pour les mêmes raisons, la notation objet indirecte (qui était de toute façon déconseillée par la communauté) a disparu.

Nouveaux concepts et fonctionnalités

[modifier | modifier le code]

Syntaxe auto-hébergée

[modifier | modifier le code]

La syntaxe de Raku est elle-même définie en Raku. Ce point qui peut paraître anodin a des conséquences très profondes sur la structure et les possibilités offertes par le langage.

En particulier, cela signifie que Raku obéit syntaxiquement aux mêmes règles que celles imposées par les fonctionnalités d'analyse textuelle du langage. Ainsi, l'analyse lexicale satisfait aux mêmes priorités que celles imposées par le traitement des expressions régulières en Raku. En l'occurrence, cette règle est, en simplifiant, celle de la plus longue unité lexicale (longuest token matching). Cette règle est fondamentale en Raku et possède une grande portée sur de nombreux aspects du langage. Par exemple, la règle de la plus longue unité lexicale permet aux noms de variables de contenir le caractère '-', sans que celui-ci soit confondu avec la soustraction.

Une autre conséquence est la possibilité pour le langage de modifier sa propre syntaxe en cours d'exécution, ce qui constitue une performance accomplie par de très rares langages de programmation, le plus emblématique étant Lisp.

Types de données

[modifier | modifier le code]

Le système statique de typage de Perl 5 comporte peu de types. Lors de la déclaration d'une variable, son sigil détermine si elle est de type scalaire, tableau ou hachage (métonyme pour table associative). Un scalaire peut contenir un entier, un flottant, une chaîne de caractères, etc. Puisque le type du contenant ne détermine que partiellement le type du contenu, on parle de typage semi-dynamique.

En Raku, les sigils et le typage dynamique de Perl 5 ont été étendus par l'addition de types statiques. Cela consiste en la déclaration explicite du type du contenant. Par exemple :

 my Int $i = 0;
 my Num $n = 3.141e0;  # le suffixe -e0 est nécessaire ici pour créer un littéral flottant.
 my Str $s = "Hello, world";

Cependant, tout comme en Perl 5, les programmeurs peuvent se passer de typage explicite :

 my $i = "25" + 10;

Le typage statique est une forme de documentation et de tests intégrée au code source. Il améliore la maintenance, spécialement dans les grands projets logiciels. Mais le typage statique alourdit le code de scripts courts ou d'unilignes. Ce style concis sans déclaration explicite de type autre que par les sigils est une force du Perl lorsqu'utilisé pour l'écriture de code à usage unique.

Raku introduit aussi des sigils secondaires appelés twigils.

Orientation objet

[modifier | modifier le code]

Perl 5 supportait l'orientation objet via un mécanisme propre à Perl et nommé bénédiction. N'importe quelle référence pouvait être bénie comme étant un objet d'une classe particulière, comme :

 # Perl 5 code
 my $object = bless $reference, 'Class';

Un objet béni pouvait alors avoir des méthodes invoquées en utilisant la « syntaxe flèche » :

 # Perl 5 code
 $objet->méthode();

L'invocation identifie la sous-routine appropriée de nom méthode, et l'appelle avec $objet comme premier argument.

Bien que très puissant (virtuellement n'importe quel autre modèle objet d'un autre langage pouvait être simulé en utilisant cette simple fonctionnalité), il rendait le cas le plus commun d'orientation objet, comme une structure C associée à du code, inutilement difficile. De plus, Perl ne pouvant faire d'hypothèse sur le modèle objet utilisé, l'invocation de méthode ne pouvait pas être très bien optimisée.

Dans l'esprit de rendre les choses simples plus simples, et les choses compliquées faciles, Raku garde le principe de bénédiction pour créer une instance pour les programmeurs qui désirent des fonctionnalités communes. Cela fournit un modèle objet plus robuste pour les cas communs. Par exemple, une classe pour encapsuler un point cartésien peut être écrite comme :

 class Point is rw {
   has ($.x, $.y);
   method gist { "Point a x=$.x y=$.y" }
 }

et utilisée :

 say my Point $point .= new: :x(1.2), :y(-3.7);
 $point.x = 1.1;
 say $point;

Le point remplace la flèche (propre à Perl 5) comme opérateur d'accès au membre d'une instance. C'est la syntaxe propre à de nombreux langages dont C++, Java, Python, et Ruby.

Notez que les méthodes « x » et « y » ne sont pas déclarées explicitement. Elles sont appelées des auto-accesseurs. Le modificateur « is rw » dans la définition de la classe permet à tous ses attributs publics d'être écrits par défaut, en utilisant les auto-accesseurs.[1]

Les données membres d'une instance sont appelées « attributs ». Elles peuvent être déclarées ainsi :

 has $.a; # mode d'accès par défaut (généralement en lecture seule)
 has $.b is rw; # accès en lecture et en écriture
 has $!c; # membre privé; pas d'accesseur public
 has $d; # comme $!d

Résolution multiple

[modifier | modifier le code]

Dans un même champ lexical, on peut définir plusieurs routines ou méthodes du même nom en les préfixant par le mot-clé multi. On parlera de multi[16] pour désigner l'ensemble des routines ou méthodes de même nom. Lors de l'appel d'une multi, la routine ou méthode dont la signature correspond aux arguments passés sera appelée. Le système de liage entre les arguments de l'appel et les paramètres de l'appelé est très pointu[17].

Ainsi, pour traverser un arbre n-aire, l'argument attendu est soit un nœud de type Nary dont les enfants sont un tableau commençant par l'$ainé et suivi éventuellement de @frères, soit une $feuille.

    multi traverser ( NAry $noeud ( :enfants [$ainé, *@frères] ) ) {
        traverser($ainé);
        traverser(:enfants(@frères));  # (lie @frères à $sommet)
    }
    multi traverser ( $feuille) {}

Ce système de multiméthodes inclut donc la fonctionnalité de filtrage par motif propre à la programmation fonctionnelle.

Expressions rationnelles

[modifier | modifier le code]

Les expressions rationnelles [18] ou expressions régulières (en anglais, regex, pour regular expression) de Perl ont connu tellement de succès qu'elles ont été mises en œuvre par une bibliothèque appelée PCRE (Perl Compatible Regular Expressions). Via PCRE, les expressions rationnelles ont été incluses sans amélioration dans beaucoup d'autres langages. Pourtant, comme le fait remarquer Larry Wall, ce sont les expressions rationnelles qui ont contribué à donner à Perl une réputation de langage peu lisible. Elles sont trop compactes et trop malignes, les mêmes caractères sont utilisés pour des usages divers. Il y a peu de support pour les captures nommées, peu de support pour les grammaires, et une intégration pauvre avec les langages réels[19].

Raku fournit un surensemble des fonctionnalités de Perl 5 concernant les expressions rationnelles. Le mécanisme des regex fournit une puissance comparable aux analyseurs syntaxiques. Ces regex agissent comme des fermetures par rapport à leur champ lexical. Les regex sont introduites avec un des mots-clefs rule, regex, token. La définition d'une regex est similaire à une définition de sous-routine et peut admettre des paramètres. Le choix du mot-clef permet de contrôler si les espaces sont significatifs ou non dans la regex, et de spécifier s'il peut y avoir retour sur trace ou non. Comme en Perl 5, on peut aussi définir des regex anonymes ou les utiliser directement dans les opérateurs m (matching) ou s (chercher et remplacer).

Seules six fonctionnalités n'ont pas été changées depuis les regex du Perl 5 :

  • Littéraux : les caractères de mots tels que « A » et souligné seront reconnus littéralement.
  • Capture : (...)
  • Alternatives : |
  • Séquences d'échappement par barre oblique inverse (backslash) : \
  • Les quantificateurs de répétition : *, +, et ?
  • Suffixe de reconnaissance minimale : *?, +?, ??

Quelques-uns des ajouts les plus efficaces sont :

  • La possibilité de référencer des règles en utilisant <rulename> pour construire des grammaires entières.
  • Des opérateurs de commission permettent au programmeur de contrôler les retours sur trace pendant la reconnaissance.

Les changements suivants ont grandement augmenté la lisibilité des regexes :

  • Simplification des groupes non-capturant : [...] qui sont les mêmes que ceux du Perl 5's : (?:...)
  • des codes assertions simplifiés : <?{...}>
  • Le /x de Perl 5 est maintenant le défaut.

Exemples :

 rx { a [ b | c ] ( d | e ) f : g }
 rx { ?( ab* ) <{ $1.size % 2 == 0 }> }

La dernière ligne est identique à :

 rx { ( ab[bb]* ) }

Comparaisons chaînées

[modifier | modifier le code]

Les nouveaux programmeurs attendent souvent que les comparaisons chaînées[20] comme dans l'uniligne ci-dessous fonctionnent :

 if 1 <= $dé1 == $dé2 <= 6 { say "Doubles!" }

En Raku, ce code fonctionne maintenant naturellement, dans l'esprit du DWIM (Do What I Mean), et s'exécute comme :

 if 1 <= $dé1 and $dé1 == $dé2 and $dé2 <= 6 { say "Doubles!" }

Évaluation paresseuse

[modifier | modifier le code]

Raku propose l'évaluation paresseuse de listes qui est une fonctionnalité de certains langages de programmation fonctionnelle tels que Haskell. L'évaluation paresseuse simplifie des tâches communes en Raku comme les opérations d'entrées/sorties, la transformation de listes et le passage d'arguments à une routine :

 my @integers = 0 .. *; # entiers de 0 à l'infini

Le code ci-dessus ne crashera pas en essayant d'assigner une liste de taille infinie à la table @integers.

Meta-opérateurs

[modifier | modifier le code]

Les méta-opérateurs sont des opérateurs qui agissent sur un autre opérateur pour obtenir un opérateur au comportement différent.

Opérateurs d'affectation

[modifier | modifier le code]

Perl5 avait hérité de certains opérateurs emblématiques du langage C tels que « += », « *= », etc. Raku généralise cette notion avec le métaopérateur d'affectation « = ».

Ainsi, pour n'importe quel opérateur binaire « op », on peut écrire :

$x op= $y; # ou encore $x [op]= $y

Pour :

$x = $x op $y;

« op » peut très bien être un opérateur défini par l'utilisateur.

hyper-opérateurs

[modifier | modifier le code]

Les hyper-opérateurs sont similaires aux opérateurs de manipulation de tableaux dynamiques du langage APL ou à l'opérateur map de Perl 5. Ils agissent sur un opérateur et le font opérer sur toutes les valeurs d'un tableau. Ainsi, pour créer un tableau dont tous les éléments sont ceux d'un tableau @a auxquels on a ajouté 1, il suffit d'écrire :

my @a-plus-un = @A »+» 1;  # aussi noté @A >>+>> 1

Opérateur de réduction

[modifier | modifier le code]

Le méta-opérateur de réduction peut travailler sur n'importe quel opérateur infixé associatif et le transformer en opérateur de liste. Tout se passe comme si le métaopérateur appliquait l'opérateur d'origine aux deux premiers éléments de la liste pour obtenir un premier résultat partiel, puis appliquait ce même opérateur au résultat partiel obtenu et à l'élément suivant de la liste pour obtenir un nouveau résultat partiel, et ainsi de suite jusqu'à la fin de la liste. Cela permet de "réduire" la liste à une seule valeur, qui pourra être, selon le cas, la somme, le produit, la moyenne, l'élément maximal, l'élément minimal, l'écart-type, etc. des éléments de la liste. C'est une construction extrêmement puissante qui promeut par exemple l'opérateur + au rang d'une fonction somme des éléments d'une liste, comme dans l'exemple ci-dessous:

say "La somme des cent premiers entiers naturels est: ", [+] ^100;

Opérateur de produit cartésien

[modifier | modifier le code]

Cet opérateur renvoie un produit cartésien entre deux ou plusieurs listes, c'est-à-dire une liste de tous les tuples possibles dans lesquels le premier élément est un élément de la première liste, le second élément un élément de la seconde liste, et ainsi de suite :

say my @chessboard = 'a'..'h' X~ 1 .. 8;

Opérateur Zip

[modifier | modifier le code]

L'opérateur zip (Z) associe deux ou plusieurs listes en intercalant les éléments de chaque liste, c'est-à-dire qu'il renvoie une liste contenant d'abord le premier élément de chaque liste en entrée, puis le second élément de chaque liste, et ainsi de suite.

say my @diagonal = 'a' .. 'h' Z~ 1 .. 8;

Opérateur d'interversion

[modifier | modifier le code]

Cet opérateur permet d'intervertir les arguments de l'opérateur d'origine.

say "un tiers est égal à ", 3 R/ 1;

Imbrication de méta-opérateurs

[modifier | modifier le code]

Les méta-opérateurs peuvent être imbriqués, quitte à utiliser des crochets (« [] ») pour désambiguïser.

@a >>>>> $b        # Comment?
@a >>[>]>> $b      # ah, oui.

Raku introduit le concept de jonctions. Nous choisissons ce terme pour le distinguer des jointures, concept propre aux bases de données relationnelles. Les jonctions sont des valeurs scalaires composites. Les jonctions ont été initialement appelées superpositions, par analogie au concept de physique quantique de superpositions quantiques — des courbes qui peuvent simultanément occuper plusieurs états jusqu'à ce que leur observation les effondre. Un module Perl 5 réalisé en l'an 2000 par Damian Conway appelé Quantum::Superpositions fournissait une preuve de concept initiale. D'abord une curiosité programmatique, les jonctions sont ensuite devenues un concept important de Raku.

Dans leur forme la plus simple, les jonctions sont créées par combinaison d'un ensemble de valeurs avec l'un des opérateurs de jonction :

 my $even_digit = 0|2|4|6|8; # any(0, 2, 4, 6, 8)
 my $odd_digits = 1&3&5&7&9; # all(1, 3, 5, 7, 9)
 my $not_zero = none(0);

Ces valeurs peuvent être utilisées arithmétiquement :

 my $jonction = 1|2|3;
 $jonction += 4; # jonction maintenant égale à 5|6|7
 $jonction += (1&2); # jonction maintenant égale(6|7|8)&(7|8|9)

ou dans des comparaisons :

 if $grade eq any('A'..'D') { say "pass" }

ou même pour l'accès à un tableau :

 if %person{any('first_name', 'nickname')} eq "Joe" { say "What do you know, Joe?" }

Les jonctions peuvent aussi être utilisées pour étendre le système de types :

 class RGB_Color is Tuple[int, 3] & Color {  }
 sub get_tint (RGB_Color|CMYK_Color $color, num $opacity where 0 <= $^opacity <= 1) {  }
 sub store_record (Record&Storable $rec) {  }

Les jonctions ne sont pas ordonnées ; 1|2|3 et 3|2|1 représentent les mêmes valeurs. Cette absence d'ordre signifie que le compilateur Raku peut choisir d'évaluer les expressions sur les jonctions en parallèle. En fait, plusieurs dans la communauté Raku croient que les jonctions peuvent surpasser l'explicite multithreading comme manière ordinaire d'accomplir le parallélisme en Raku.

Parallélisme et multitâche

[modifier | modifier le code]

Comme beaucoup de langages modernes, Raku a été conçu pour permettre le parallélisme, c'est-à-dire l'exécution de plusieurs tâches en même temps, et la programmation asynchrone (parfois appelée programmation événementielle), c'est-à-dire qu'un événement ou un changement dans une partie d'un programme peut conduire à un autre événement ou changement dans une autre partie d'un programme, de façon asynchrone par rapport au flot normal d'exécution d'un programme.

Raku offre une interface modulaire et cohérente de haut niveau au parallélisme, indépendante de la façon dont une machine virtuelle pourrait mettre en œuvre cette interface pour un système d'exploitation donné. De plus, certaines fonctionnalités de Perl peuvent opérer implicitement de façon asynchrone. Pour permettre une interopérabilité maîtrisée et prévisible de ces fonctionnalités, le code utilisateur utilise, dans la mesure du possible, des interfaces de haut niveau et évite d'utiliser les interfaces de bas niveau (threads, ordonnanceurs, verrous, etc.). Outre le fait qu'ils ne fonctionnent pas de la même façon dans les différents systèmes d'exploitation ou environnements d'exécution, ces mécanismes de bas niveau sont notoirement très délicats à programmer et à maîtriser dans la plupart des langages de programmation qui les mettent en œuvre (et les threads de Perl 5 ne font pas exception).

L'entité centrale de ces mécanismes de haut niveau est la promesse, qui représente le résultat d'un calcul qui n'est peut-être pas terminé au moment où la promesse est obtenue. Les promesses offrent l'essentiel de ce dont a besoin du code utilisateur pour opérer de façon parallèle ou asynchrone. Un programme peut tenir sa promesse (fournir le résultat) ou la rompre (échouer à fournir ce résultat). Une promesse peut avoir trois statuts: planifié (pas encore exigé), tenu ou rompue. Une bonne partie de la puissance des promesses provient du fait qu'il est possible de les combiner ou de les enchaîner:

my $promesse1 = Promise.new();
my $promesse2 = $promesse1.then( { say "Résultat de la seconde promesse"});

Ici, le then ordonnance le code de la promesse 2 en sorte qu'il s'exécute quand la promesse 1 sera tenue (ou rompue).

Il existe aussi des fournisseurs (Supply), qui offrent un mécanisme de flux de données asynchrone qui peut être consommé simultanément par un ou plusieurs consommateurs d'une manière analogue aux événements dans d'autres langages de programmation. On peut s'en servir pour mettre en place des schémas de programmation événementielle.

Enfin, un canal (Channel) est une queue ou file d'attente qui peut avoir plusieurs lecteurs et plusieurs rédacteurs, analogue à une file FIFO (premier entré, premier sorti) qui autoriserait les communications inter-processus.

Dans les langages de bas niveau, le concept de macros a été synonyme de substitutions textuelles du code source à cause de la large utilisation d'un préprocesseur ignorant la syntaxe du langage. Le langage C utilise la construction #define. Perl 5 utilise des systèmes de filtres sources à cet effet. Ils sont notoirement peu fiables, car leur empilement a des effets aléatoires. En effet, chaque filtre suppose que le code qu'il filtre est du code Perl 5 alors qu'il reçoit du code modifié par ses prédécesseurs.


Lisp est privilégié, car il propose un système de macros qui manipulent directement l'arbre syntaxique correspondant au code source du programme. C'est facile, car sa syntaxe concrète est identique à sa syntaxe abstraite. À terme, Raku vise à intégrer un système de macro tout aussi puissant qu'en Lisp, ce qui constitue l'un des objectifs les plus ambitieux du langage.

Raku proposera les deux types de macro[21] : substitutions textuelles et manipulation de l'AST.


Une définition de macro Raku ressemblera à une définition de sous-routine ou méthode, et peut travailler sur des chaînes non analysées, un arbre de syntaxe abstrait AST représentant du code préanalysé, ou encore une combinaison des deux. Une définition de macro pourrait ressembler à :

macro hello($what) {
  quasi { say "Hello { {{{$what}}} }" };
}

Dans cet exemple particulier, la macro n'est pas plus complexe qu'une substitution textuelle en C, mais parce que l'analyse du paramètre de la macro se produit avant que la macro n'opère sur le code appelé, les messages de diagnostic seront beaucoup plus informatifs. Cependant, parce que le corps de la macro est compilé à chaque lancement du programme, diverses techniques d'optimisation peuvent être employées.

Hello world

[modifier | modifier le code]

En Raku comme en Perl 5, on peut écrire

   print "Hello world\n";

En Raku, on préfèrera écrire le hello world ainsi :

 say "Hello world";

say est semblable au say de REXX, au writeln de Pascal et au puts de Ruby et C.

Comme en Perl 5, les JAPHs (programmes qui impriment « Just another Perl hacker »), sont de bons moyens d'expérimentation avec Raku.

Ici un exemple de curryfication :

 sub japh (Str $lang) { say "just another $lang hacker"; }
 my &perl6Japh := &japh.assuming("Perl6");
 perl6Japh();

Liens externes

[modifier | modifier le code]

Notes et références

[modifier | modifier le code]
  1. « Christmas is here. », sur Perl 6 Advent Calendar, (consulté le ).
  2. « https://github.com/perl6/roast/blob/master/docs/announce/6.d.md#changelog » (consulté le )
  3. « https://github.com/rakudo/rakudo/blob/master/LICENSE », (consulté le )
  4. (en) Pourquoi Raku?
  5. suite de tests officielle, sur github
  6. Apocalypse 1
  7. (en) « A VM for NQP And Rakudo Perl 6 ».
  8. « Announce: Rakudo Star Release 2015.11 », (consulté le ).
  9. (en) annonce de Larry Wall sur Twitter, «Perl 6 goes live at 2015-12-25 22:00 GMT, a test suite and compiler, as promised. God bless us, everyone!»
  10. annonce de la version Christmas, décembre 2015 sur github
  11. « camelia », sur dépôt svn de pugs, (consulté le ).
  12. Larry Wall, « Roles and Parametric Types », sur perlcabal.org, (consulté le ).
  13. « This is Rakudo Star, a useful, usable Perl 6 distribution for "early adopters". » README du projet
  14. Patrick Michaud, « Annonce de Rakudo Star », sur rakudo.org, (consulté le ).
  15. Cependant le système de prototypes, ajout tardif au langage Perl 5, est un moyen de vérification du nombre de paramètres et une faible vérification de type
  16. Larry Wall, « Unpacking tree node parameters », sur perlcabal.org, (consulté le ).
  17. Jonathan Worthington, « The new Rakudo signature binder has landed », sur useperl.org, (consulté le ).
  18. Larry Wall, « Regexes and Rules », sur perlcabal.org, (consulté le ).
  19. Larry Wall, « Pattern Matching », sur dev.perl.org, (consulté le ).
  20. Larry Wall, « Chained Comparaisons », sur feather.perl6.nl, (consulté le ).
  21. Larry Wall, « Macros », sur feather.perl6.nl, (consulté le ).