Last active
March 25, 2021 22:38
-
-
Save cognominal/387a169ce262d7c1fb691ff3e58a2bb1 to your computer and use it in GitHub Desktop.
presentation #prez
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| =begin pod | |
| =head1 Cette présentation | |
| Stéphane cognominal Payrard -- Journées Perl 2016 -- Samedi 25 Juin 2016 | |
| Ce talk | |
| =item Objet et sa place dans les types Perl | |
| =item Multiméthodes | |
| =item Métamodèle OO | |
| =head2 | |
| Ce document est dérivé de la présentation censément sur l'objet aux | |
| journées Perl 2016. J'y rajoute sous les =head2 de pod du matériel | |
| que j'y ai fait oralement mais aussi du matériel trop avancé | |
| concernant le compilateur. Il découle d'une démarche commencée en | |
| 2012 qui consiste à explorer l'architecture de rakudo en expérimentant | |
| avec le REPL. Dans ce document écrit je ne gommerai pas les | |
| difficultés que j'ai omise à l'oral. Lors de la présentation orale, | |
| j'ai évité les "forward references", elles sont moins gếnantes à | |
| l'écrit. Expérimenter pour apprendre Raku a aussi pour conséquence | |
| d'explorer des zones peu connues et de découvrir des bogues qui sont | |
| généralement corrigés rapidement par la core team. Il n'y a donc pas | |
| de honte à n'être, comme moi, que la mouche du coche. | |
| =head1 Si Raku installé, utiliser le REPL | |
| =item Pas de perte de la portée lexicale | |
| =item Chaque ligne fait un EVAL | |
| =item ... dans une portee emboitée | |
| $ Raku-m # avec le backend MoarVM | |
| To exit type ' exit' or '^D' | |
| > say 'Salut les mongueurs' | |
| Salut les mongueurs | |
| > 'Salut les mongueurs' | |
| Salut les mongueurs | |
| > my $a = 'salut' | |
| salut | |
| > $a | |
| salut | |
| > { my $a } | |
| > $a # le contexte lexical n'est plus accessible | |
| Variable '$a' is not declared | |
| > $a # le mode de Raku est strict par défaut. Déclaration lexicale nécessaire | |
| Variable '$a' is not declared | |
| > no strict; $a | |
| > (Any) | |
| > $a | |
| > (Any) | |
| > class A {} | |
| (A) | |
| > class A {} | |
| Redeclaration of symbol A | |
| =head2 Notes sur le REPL | |
| Les lignes d'une session REPL sont montrées consécutivement | |
| Le REPL est un concept hérité de LISP et permet d'utiliser | |
| interactivement le langage. C'est l'acronyme de Read Eval Print Loop. | |
| En clair. chaque ligne est lue, évaluée par EVAL, la valeur est | |
| automatiquement imprimée et ce ad nauseamn. Chaque ligne est | |
| interprétée dans un contexte lexical nouveau imbriqué dans le | |
| précédent de sorte qu'une variable lexicale déclarée précédemment sans | |
| contexte lexical explicite est visible. Lors d'expérimentation à la | |
| ligne de commande, c'est une nuisance de devoir déclarer les | |
| variables. Heureusement, la portée du pragma C<no script> est | |
| lexicale donc permet de ne pas avoir à déclarer les variables. | |
| Redéclarer des symbole, comme une classe, dans une portée de paquetage est toujours une erreur. | |
| Mais pour supporter cette fonctionnilité, il faudrait un moyen de savoir d'où vient une variable | |
| quand elle peut venir de différentes "versions" d'une portée paquetage donnée. | |
| =head1 Expérimenter avec Raku sans l'installer | |
| Utiliser le bot p6eval | |
| =item grâce à IRC | |
| =item aller sur irc.freenode.net | |
| =item /join #Raku | |
| =item m: say "hello world" # en public | |
| =item /msg camelia m: say "hello world" # en privé | |
| =item sur irc.perl.org #perlfr le bot s'appelle p6eval | |
| =item affichage explicite contrairement au REPL | |
| =head2 Limite du bot | |
| On ne peut avoir de "session" contrairement au REPL puisqu'à chaque ligne | |
| r>akudo est relancé. | |
| =head1 Présentation suivante : les roles | |
| =item roles comme interface matérialisé par les sigils | |
| =item roles paramétriques, un peu comme generics de Java | |
| =head2 d'après jnthn | |
| J'ai utilisé les slides de jnthn. | |
| voir L<Raku roles in depth|http://jnthn.net/papers/2009-yapc-eu-roles-slides.pdf>. | |
| On peut voir ce document comme un complément au cours de jnthn sur les internals de | |
| rakudo et nqp | |
| [L<1|http://edumentab.github.io/rakudo-and-nqp-internals-course/slides-day1.pdf>] | |
| [L<2|http://edumentab.github.io/rakudo-and-nqp-internals-course/slides-day2.pdf>] | |
| Les ops de AST sont documentés | |
| [L<ici|https://github.com/Raku/nqp/blob/master/docs/ops.markdown>] et | |
| l'implémentation des ops de MoarVM est | |
| L<ici|https://github.com/MoarVM/MoarVM/blob/master/src/core/interp.c>. | |
| L'AST étant par définition Abstract, il n'y a pas toujours de | |
| correspondance exacte entre les ops de l'AST et ceux de MoarVM. Les | |
| ops spécifiques à Raku sont implémentés | |
| C<ici|https://github.com/rakudo/rakudo/blob/nom/src/vm/moar/ops/Raku_ops.c>. | |
| =head1 Distinction entre rôle et classe | |
| =item Une classe permet d'instancier des objets | |
| =item On peut composer des classes à partir de roles | |
| =item Classes mutables, roles, pas | |
| =item Mais on peut mixer des roles dans un classe/objet | |
| =item statiquement : trait dynamiquement : mixin | |
| class A {}; class A is B {} | |
| implémenté en terme de : | |
| multi sub trait_mod:<is>(Mu:U $child, Mu:U $parent) { ... } | |
| =head2 | |
| Les traits et les mixins sont implémentés en term de multiméthodes C<trait_mode>. | |
| C<< :<is< >> dé | |
| =head1 Programmation Orientée Objet en Raku | |
| =item OO à base de classes versus prototpypes | |
| =item Raku à base de classes | |
| =item Mais métamodèle permet d'implémenter OO à base de prototypes | |
| =item Multiméthodes | |
| =item Rôles (prochaine présentation) | |
| =item Tous les types de Raku ne sont pas objets | |
| =item process multifils et intérêt de l'immutabilité | |
| =head2 OO | |
| Il y a deux genres de programmation objet selon le modèle utilisé pour | |
| crééer des objets. On peut les crééer à partir d'objet prototypes ou | |
| en les instanciant avec l'aide de la classe appropriée. La plupart des | |
| langages OO populaires sont à base de classes, comme Java ou C++, mais | |
| Javascript à base de prototypes. | |
| Une méthode est une routine dont le premier paramètre est l´invocant. | |
| Les routines ont une signature qui fait partie de son nom long. | |
| Plusieurs routine de meme non court sont distinguées par leur signature | |
| Généralement on appelle une routine avec son nom court, le dispatch se | |
| fait avec la routine de signature la plus spécifique. | |
| Tous les types de Raku ne sont pas objets. | |
| Je ne parlerais pas de concurrence mais elle a une influence sur la nature | |
| des données. Pour que des fils (threads) puissent travailler sur | |
| les memes données sans soucis de coordination, il faut qu´elles soient immutables | |
| =head1 Attributs d´objet et accesseur | |
| class A { | |
| has int $!val = 42; | |
| has $.b is rw; | |
| } | |
| twigil ! pour attribut privé non accessible classes dérivées | |
| twigil . pour attribut public | |
| is rw pour attribut en lecture écriture | |
| my A $a = ... | |
| say $a.b # accesseur en lecture <=> appel de méthode | |
| $a.b = 666 # acesseur en écriture | |
| =head1 Méthodes | |
| class Salut { | |
| has $.qui is required; | |
| method salut { say "salut $!qui" } | |
| } | |
| $_ = Salut.new(:qui<dude>); # .new utilise argument nommés | |
| $_.salut; | |
| .salut; # invocant implicite | |
| =head1 Syntaxe pour une classe par fichier | |
| unit class Salut; | |
| has $.qui | |
| method salut() { say "salut $!qui" }my | |
| =head1 Invocant et pseudo-classe | |
| =item invocant par défaut est self | |
| =item pamètre invocant généralement omis de la sigature | |
| =item si explictite, le : separe l'invocant des autres parametres | |
| =item ::?CLASS permet de capturer la classe | |
| =item utile pour classe anonyme | |
| =item ou pour éviter d'utiliser le nom | |
| class A { | |
| method bar { self.doit } | |
| method doit($self:) { ... } | |
| method foo(::?CLASS $self) { | |
| my ::?CLASS $a | |
| } | |
| } | |
| =head1 Instanciation de classes | |
| class Salut { | |
| has $.qui | |
| method salut($quoi) { say "$quoi $!qui" } | |
| } | |
| $_ = Salut.new(:qui<dude>); | |
| .salut: bonjour; | |
| .salut(´bonjour´) | |
| salut $_: | |
| =head1 Attributs et méthodes de classe | |
| Une classe est un module donc déclarateur de scope classique. | |
| =item my : privé | |
| =item our : public | |
| method oh_so_static(::?CLASS:U:) { } | |
| method oh_so_static(A:U:) { } | |
| Explication de signature | |
| =item A nom de classe | |
| =item A:U valeur indéfinie seulement, donc classe pas instance | |
| =item A:U: le paramètre est invocant | |
| =head1 Types et valeurs de défaut des attributs | |
| =item les attributs ont un sigil ! même si déclaré avec . | |
| =item le type implicite d'un attribut est Mu | |
| =item pour accepter les Junctions, dérivé de Mu | |
| =item mais initialisé par défaut à Any | |
| > class A { has $.a; has $!b }; A.^attributes | |
| (Mu $!a Mu $!b) | |
| > say A.new( :a(1|2)).a.WHAT | |
| (Junction) | |
| > A.new.a.WHAT | |
| (Any) | |
| =head1 Accesseur d'attribut rw ou méthode lvalue ? | |
| Même interface pour l'utilisateur | |
| =item l'utilisateur d'une classe n'a pas à connaître ses attributs | |
| =item détail d'implémentation qui peut changer | |
| =item même si attribut publique | |
| =item la méthode .b remplace l'accesseur autogénéré | |
| =item .quelquechose : point comme pseudosigil pour désigner une méthode | |
| method b is rw { | |
| return Proxy.new( | |
| FETCH => method () { say 'fetch'; $!b }, | |
| STORE => method ($new) { say 'store' $!b }, | |
| ); | |
| } | |
| =head1 Containers | |
| =item un Proxy est une forme de container | |
| =item Scalar est le container par défaut | |
| =item .VAR donne le container d'une valeur | |
| =item .WHAT donne le type d'une valeur | |
| =item .VAR et .WHAT sont des macros | |
| > my $a; say $a.VAR.WHAT | |
| (Scalar) | |
| my $a; say $a.VAR # bogue. Décontenairisation parasite | |
| Any | |
| =head2 | |
| =head1 Retour sur le container Proxy | |
| #Raku++ timotimo++ pour l'exemple | |
| my $foo := Proxy.new( | |
| FETCH => -> | { "yo" }, | |
| STORE => -> | { }); | |
| say $foo.VAR.WHAT; | |
| say $foo | |
| (Proxy) | |
| yo | |
| =head1 Types | |
| int, num, int8... types natifs dont la valeur tient dans un registre | |
| types natifs | |
| objets | |
| =item les types natifs n'ont pas d'annotation de type, | |
| =item les objets, si | |
| =item mais autoboxing: 1.WHAT | |
| =head1 Boxing | |
| =item On peut traiter les types natifs comme des objets | |
| =item Boxing | |
| =item On ne peut "interroger un natif" que par un boxing | |
| =item Transparent pour le programmeur | |
| =item Boxing d'un int donne un Int | |
| =item Boxing se cumule avec les containers | |
| =head1 Exemple de boxing | |
| > my int $i = 42 | |
| 42 | |
| > say $i | |
| 42 | |
| > $i.say # boxing pour utiliser la méthode .say | |
| 42 | |
| > $i.WHAT | |
| (Int) | |
| > $i.REPR | |
| P6opaque # classes Raku implémentées en terme de P6Opaque | |
| > | |
| =head1 Type valeur et type référence (1) | |
| Un objet est un type référence. | |
| Il peut etre modifié si passé en argument et si mutable | |
| class A { has $.a is rw }; | |
| sub foo(A $val) { $val.a = 42 } | |
| my $a = A.new; # A.new(a => Any ) | |
| a($a); | |
| say $a; # A.new(a => 42 ) | |
| > my int $foo = 10; | |
| > sub do-it(int $bar is rw) { say $bar.VAR.WHAT }; | |
| > do-it($foo) | |
| (IntLexRef) | |
| =head1 Type valeur et type référence (2) | |
| sub foo(int $val) { $val = 42 }; | |
| Cannot assign to readonly variable $val | |
| =item $val est passé par référence et peut etre modifié | |
| =head1 Passer par réference | |
| sub foo(int $val is rw) { $val = 42 }; my int $i = 0; foo($i) ; say $i | |
| foo(666) | |
| Expected a modifiable native int argument for '$val' | |
| =head1 Egalité et identité | |
| Opérateurs binaires (arité 2) | |
| =item =:= vrai identité | |
| =item eqv équivalence | |
| =item === identité de valeur | |
| =item == conversion des args à Num avant comparaison | |
| =item eq conversion des args à Str avant comparaison | |
| =head1 Opérateurs sont des exemples de multi subs | |
| =item Noms longs avec des paires adverbiales | |
| multi sub infix:<eq>(\a, \b) { a.Stringy eq b.Stringy } | |
| multi sub infix:<eq>(str $a, str $b) returns Bool:D { ... } | |
| ... | |
| multi sub infix:<==>(\a, \b) { a.Numeric == b.Numeric } | |
| =head1 Pseudo sigil backslash | |
| multi sub infix:<eq>(\a, \b) { a.Stringy eq b.Stringy } | |
| =item pseudo sigil \ => pas de containers | |
| > my \a = 1; | |
| 1 | |
| > say \a; | |
| \(1) | |
| > \a = 2; | |
| \(1) | |
| Cannot modify an immutable Capture | |
| in block <unit> at <unknown file> line 1 | |
| =head1 Un exemple de multisub | |
| multi quicksort( [ ] ) { () } | |
| multi quicksort( [$x ] ) { ($x) } | |
| multi quicksort( [$pivot, *@xs ] ) { | |
| quicksort(@xs.grep: * before $pivot), | |
| $pivot, | |
| quicksort(@xs.grep: * !before $pivot), | |
| } | |
| =head1 Quelques exemples | |
| > 'ab' === 'a' ~ 'b' | |
| True | |
| > 'ab' eq 'a' ~ 'b' | |
| True | |
| > 'ab' =:= 'a' ~ 'b' | |
| False | |
| > 'ab' =:= 'ab' | |
| True | |
| > | |
| =head1 Liage dynamique (binding) et affectation | |
| =item Liage : lie un nom | |
| =item Associe un nom à une valeur ou alias une variable. | |
| =item Similaire à un typeglob Perl 5 | |
| =item nqp::bind | |
| =item Affectation | |
| =item multisub | |
| > my @a := 1, 2, 3; say @a.WHAT | |
| (List) | |
| > my @a := 1, 2, 3; my @b := @a; my $c := @a; say @a =:= @b =:= $c | |
| True | |
| > @a.VAR =:= @b.VAR =:= $c.VAR | |
| True | |
| > my @a = 1, 2, 3; say @a.WHAT | |
| (Array) | |
| for 1..20 { print $_, Int.new($_) =:= Int.new($_) ?? '' !! '!', ' ' } | |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15! 16! 17! 18! 19! 20! | |
| =head1 Immutabilité et conteneur | |
| Une valeur immutable est une valeur qu'on ne peux pas modifier | |
| en place; càd sans changer son identité | |
| =head1 Immutabilité : listes, tableaux (1) | |
| Une liste est immutable. Un tableau ne l'est pas. | |
| Liage d'une lise à un Positional. | |
| > my @a := 1, 2, 3 ; @a[0] = 4 | |
| Cannot modify an immutable Int | |
| in block <unit> at <unknown file> line 1 | |
| > @a.push: 4 | |
| Cannot call 'push' on an immutable 'List' | |
| in block <unit> at <unknown file> line 1 | |
| > @a.WHAT | |
| (List) | |
| > @a.push: 4 | |
| Cannot call 'push' on an immutable 'List' | |
| in block <unit> at <unknown file> line 1 | |
| Assignement d'une liste à un Positional | |
| > my @a = 1, 2, 3 ; @a[0] = 42; @a | |
| [42 2 3] | |
| =head1 Immutabilité : listes, tableaux (2) | |
| Mais les conteneurs d'une liste sont mutables | |
| > my $a = 0; my @a = ($a, 1, 2 ) | |
| [0 1 2] | |
| > my $a = 0; my @a := ($a, 1, 2 ) | |
| (0 1 2) | |
| > @a[0] = 42 | |
| 42 | |
| > @a | |
| (42 1 2) | |
| =head1 Identité de conteneur | |
| VAR($a) =:= VAR($b) | |
| =head1 Déclaration de type | |
| my int $value | |
| int : commence par une minuscule -> non objet | |
| Int : majustcule -> objet | |
| nqp | |
| > my int $a := 1 ; use nqp; say(nqp::isint($a)) | |
| 1 | |
| rakudo | |
| > my int $a := 1 ; use nqp; say(nqp::isint(nqp::decont($a))) | |
| 1 | |
| =head1 Mu, Any, Junction, Cool, Failure, | |
| =item Mu : classe racine | |
| =item Junction : valeur quantique, parallélisme potentiel | |
| =item Any is Mu : racine de non Junction | |
| =item Cool is Any : | |
| =head1 Junction | |
| > 1|2|3 == 3 | |
| False | |
| False | |
| True | |
| > ?(1|2|3 == 3) | |
| True | |
| > say ((1|2|3) == 3).WHAT | |
| (Junction) | |
| > | |
| =head1 .perl, .gist, .Str | |
| =item .Str convertit une valeur en chaîne | |
| =item .gist même chose à usage humain | |
| =item .perl code pour recréer la valeur | |
| > class A {}; my $a = A.new; | |
| A.new | |
| > use MONKEY-SEE-NO-EVAL; EVAL( $a.perl ) eqv $a | |
| True | |
| =head1 .perl, .gist, .Str sur classes et instances | |
| > class A { has $.a }; my $a = A.new | |
| A.new(a => Any) | |
| > A.Str | |
| Use of uninitialized value of type A in string context | |
| Any of .^name, .perl, .gist, or .say can stringify undefined things, if needed. | |
| > $a.Str | |
| A<86630344> | |
| > A.gist, $a.gist | |
| ((A) A.new(a => Any)) | |
| > A.perl, $a.perl | |
| (A A.new(a => Any)) | |
| =head1 .perl, .gist, .Str sur un match | |
| > 'ab' ~~ /(a) $<b>=b / | |
| 「ab」 | |
| 0 => 「a」 | |
| b => 「b」 | |
| > $/.Str | |
| ab | |
| > $/.gist | |
| 「ab」 | |
| 0 => 「a」 | |
| b => 「b」 | |
| > $/.perl # ci-dessous, j'ai raccourci la sortie | |
| Match.new(ast => Any, list => (Match.new(ast => Any, list => (), hash => Map.new(())...)) | |
| =head1 Métamodèle | |
| =item soubassement du système de classes de Raku | |
| =item + ou - autohébergé | |
| =item macro .HOW pour accéder la métaclasse | |
| > Mu.HOW | |
| Raku::Metamodel::ClassHOW.new | |
| > Mu.HOW.name(Mu) | |
| Mu | |
| > Mu.HOW.^name | |
| Mu | |
| > Mu.HOW.HOW.^name | |
| NQPClassHOW | |
| =head1 Métamodèle | |
| > 42.^parents() | |
| () | |
| > 42.^parents(:all) | |
| ((Cool) (Any) (Mu)) | |
| > Mu.^methods | |
| (self sink ACCEPTS WHERE WHICH split take return-rw return WHY set_why Bool ... ) | |
| > Mu.^can('Str') | |
| (Str) | |
| > Mu.^can('Foobar') | |
| () | |
| > 1.^can('Str') | |
| (Str Str!b | |
| > 1.^can('Str')[0].WHAT | |
| (Method) | |
| > 1.^can('Str')[0].signature | |
| (Mu $: | is raw) | |
| =head1 multiméthodes et grammaire | |
| Avec les classes, le dispatcher choisit la méthode | |
| dont la signature est au plus près des arguments. | |
| La signature la plus précise l'emporte. | |
| Avec les grammaires, on génère un NFA (non deterministic | |
| finite automaton), ce qui signifie que les règles sont | |
| entrées conceptuellement en para | |
| grammar A { | |
| token TOP { <a> } | |
| proto token a { <...> } | |
| token a:sym<a> { 'a' } | |
| token a:sym<aa> { 'aa' } | |
| } | |
| say A.parse('aa'); | |
| =head1 Résumé : les concepts clé | |
| =item objet, classe, instance | |
| =item concret, défini, vrai | |
| =item mutable, container | |
| =item sigil, twigil | |
| =item role, itération | |
| =item trait, attribut, | |
| =item identité, égalité | |
| =end pod |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment