Découverte du langage Pony

a marqué ce sujet comme résolu.

Bonjour.

Voici le premier jet d'un article d'introduction au langage Pony.

Un point qui me semble important, je fais partie de la core team derrière Pony ; je suis donc particulièrement intéressé par les possibles retours sur ma partialité ou sur les points inutilement détaillés (je suis parfois trop entraîné dans mon explication sans m'en rendre compte).

Merci !

+2 -0

Bonjour Praetonus,

Je ferai une vrai relecture dans les jours qui viennent, mais il manque pour l'instant quelque chose d'important : une bonne introduction. Ce serait bien de dire en quelque lignes les atouts et les domaines privilégiés de Pony. Une description rapide du langage. Pour l'instant, ton introduction est

Bonjour et bienvenue. Dans cet article, nous allons parler du langage Pony, un jeune langage fort sympathique.

La philosophie Pony est « get stuff done ». Le langage est un outil pour résoudre des problèmes spécifiques. En particulier, l'un des problèmes visés par Pony est « comment construire un modèle de parallélisme sûr et performant ? » Les armes de Pony pour répondre à ce problème sont séparées principalement en deux champs.

La seule chose qu'on sait est que Pony est adapté au parallélisme. Ok, mais vise-t-il plutôt le web, des programmes, le calcul scientifique, est-il est multisystème, cherche-t-il les performances, la sécurité, est-il fonctionnel ou impératif, plutôt script ou compilation ?

J'imagine qu'une partie des réponses se trouve plus bas, mais dès la fin des lignes que je cite au-dessus, on entre dans une description plus longue de certaines fonctionnalités du langage. Ce serait bien de mettre ces infos (ou une partie d'entre elle) dans une vrai introduction. Quelque chose qui nous pousse à nous dire « ce langage à l'air intéressant, lisons donc cet article ». ;)

+4 -0

Parallélisme et/ou concurrence ? J'ai l'impression que l'article mélange les deux notions.

Une explication en français ici (dans mon article sur la prog asynchrone), ou plus crédible et certainement plus complet, par Rob Pike (en anglais, slides ) :

En très résumé, que fait Pony s'il n'a qu'un seul CPU à sa disposition ?

D'ailleurs, où est-ce que le langage se situe par rapport à Go qui semble être très, très cousin sur la catégorie de problèmes que Pony cherche à résoudre. Un petit mot sur les sources d'inspiration ?

+2 -0

Chouette article, merci et bravo !

Pony est un langage orienté acteurs.

J'aime pas trop cette phrase. Je dirais plutôt que Pony est orienté objet, et se base sur le modèle d'acteur.

Je connais moins Pony qu'Erlang/Elixir, mais j'ai cette impression :

Langages pour la prog concurrente avec actor modèle :

  • OO : Pony
  • Fonctionnel : Erlang / Elixir

Je rejoins la remarque de nohar à propos du parallélisme. C'est bien la concurrence qui fait la force de Pony ou Erlang. Un CPU ? Pas de problème, ça se planifie. 12 CPU ? C'est pareil ! Juste un peu plus de boulot pour le scheduler. 24 CPU sur 12 différents serveurs ? Pas de problème, suffit que les schedulers se passent bien les messages.

C'est ça qui est fun historiquement avec Erlang par exemple, de mon point de vue. On avait des Pentium 2 à 200MhZ, donc il a fallu distribuer, donc il a fallu avoir une bonne plateforme/langage concurrent. Il y a quelques années avec l'arrivée des multicore, les malins se sont dit "Bon ben on a déjà tout en place pour faire tourner un truc sur 1000 machines, faire tourner un truc sur une seule machine qui a 1000 coeurs c'est easy peasy". Et c'est probablement une des raisons du grand regain d'intérêt pour BEAM à mon avis.

+1 -0

Gabbro : Je vais revoir ça.

nohar : En effet, les acteurs expriment plutôt la concurrence. En monocœur, on aura (par défaut) un seul scheduler (donc un seul thread). Pour Go et Pony, ils jouent globalement dans la même cour, la principale différence est que Go a des paradigmes bloquants, contrairement à Pony. Go peut deadlock, Pony non. De plus, Go n'est pas data-race free. J'ajouterai un paragraphe sur l'historique du langage et les inspirations.

victor : Ta formulation pour les acteurs semble en effet plus adéquate. Concernant OO vs fonctionnel, le langage est plutôt un mix des deux. Il y a des structures OO basiques (pas d'héritage) mais le système de types fait penser à un langage fonctionnel. Pour l'anecdote, Sylvan Clebsch, le designer principal du langage, répond « oui » à la question « Pony est-il orienté objet ou fonctionnel ? »

Merci pour vos remarques.

PS : Au passage, concernant la coloration syntaxique, j'ai soumis une PR sur le dépôt de pygments (il me semble que c'est ce que ZdS utilise) il y a quelques temps, qui ne semble pas avoir attiré l'attention d'un mainteneur. Il y a un tas de PR inactives dans le dépôt, quelqu'un saurait si le projet est abandonné ? Si c'est le cas, il y aurait-il un autre moyen pour ajouter un langage à la coloration syntaxique de ZdS ? J'aimerais bien que le code Pony soit formaté correctement avant la publication de l'article.

+0 -0

victor : Ta formulation pour les acteurs semble en effet plus adéquate. Concernant OO vs fonctionnel, le langage est plutôt un mix des deux. Il y a des structures OO basiques (pas d'héritage) mais le système de types fait penser à un langage fonctionnel. Pour l'anecdote, Sylvan Clebsch, le designer principal du langage, répond « oui » à la question « Pony est-il orienté objet ou fonctionnel ? »

Praetonus

Je pense que tu confonds un peu typage et paradigme. Il y a un bon nombre de langages fonctionnels qui contrairement à Pony ne sont pas statiquement typés. Toujours pour garder le parallèle, regarde Erlang ou Elixir.

On pourrait dire aussi que Pony est OO, mais que son système de type fait penser à un langage OO (Java, Cpp). Plus sérieusement, la homepage de Pony dit que Pony est OO, idem sur GitHub : https://github.com/ponylang/ponyc , et peu de choses me font penser qu'il est multiparadigme OO/fonctionnel.

Quels aspects fonctionnels vois-tu dans Pony ?

+1 -0

Le fait que tout soit expression, pour commencer. Ensuite, il y a du filtrage de motifs et de l'application partielle de fonction. Et si on se cantonne aux reference capabilities val et box, sans acteurs ni FFI, on se retrouve avec un langage fonctionnel pur. En ajoutant les acteurs par dessus, on obtient grosso-modo les mêmes concepts qu'Erlang (par contre ça sera minable niveau perfs, les acteurs Pony ne sont pas pensés pour avoir un état immuable).

+0 -0

Cool, je trouve beaucoup mieux. :)

J'ai une question par rapport à l'exemple de filtrage de motif :

1
2
3
4
5
6
7
8
let x: (String | None)
match x
| None => foo()
| "abc" => bar()
| let s: String if s.contains("str") => baz()
else
  bat()
end

Tu as dit plus haut ici que tout est expression, du coup le match retourne une valeur. Donc pour la capturer, il faudrait pas un = à la fin de la ligne let et indenter le match pour rendre la chose plus claire ?

+0 -0

Cool, je me réjouis de voir. Je trouve super d'avoir un article sur un sujet dont on parle peu.

Je serai peut-être pas le seul à trouver l'article intéressant mais à ne pas comprendre l'avantage de Pony sur ses concurrents, disons par exemple Erlang/OTP/BEAM. A part que le GC collecte les process.

+0 -0

Le principal avantage, par rapport à Erlang en l'occurrence, c'est la vitesse intrinsèque du langage. Erlang copie le contenu de tous les messages et implémente ses files de messages avec des mutex. Pony n'a pas besoin de copier grâces aux garanties des reference capabilities et les files de messages ont une simple instruction atomique sur le push et sur le pop. Ce ne sont pas les seuls éléments mais ça joue énormément. Il y a quelques benchmarks dans un des papiers.

Par rapport à d'autres langages à acteurs, comme Scala par exemple, où le contenu des messages n'est pas copié, l'avantage est également au niveau de la sûreté. Il est possible d'avoir des data races en Scala, pas en Pony. De plus, la différence de performances est notable ici aussi.

Je vais ajouter quelques mots sur ça dans l'article.

+2 -0

Merci pour l'explication ! C'est exactement le genre d'explication qui me manquait dans ton article. :)

Du coup on pourrait dire que Pony est un genre d'Erlang mais mieux adapté à des calculs importants. C'est intéressant ça. Erlang a de très jolies feintes de sorte que l'immutabilité - et donc parfois la copie - ne pose pas de problème. Par exemple l'usage de ropes pour les strings.

Mais effectivement, des fois on pense à Erlang pour par exemple distribuer du calcul, mais ce serait mieux avec Pony.

+0 -0

Bonjour.

La bêta a été mise à jour.

  • Ajout de la section « Pony est-il le bon outil pour vous ? »
  • Ajout du chaînage de méthodes dans la section « Où l'on parle d'expressions ». Il s'agit d'une nouvelle feature tout juste finalisée.

Merci d'avance pour vos commentaires.

+0 -0

Bonjour, comme promis, le retour complet,

Avertissement d'usage : j'ai tendance à être assez lourd lors des béta. Mon but n'est nullement de taper sur ton texte, mais bel et bien de pointer ce qui m'a gêné pour t'aide à l'améliorer. Ceci n'est en aucun cas une attaque personnelle.1


Impression globale (faite après la lecture du contenu en entier) :

  • L'intro est beaucoup mieux. N'hésite pas à refaire une passe dessus et à étoffer ce que tu penses possible. ;)
  • Le passage sur les types est lourd, long, et on ne sait pas où on va. C'est d'autant plus gênant que c'est la première vraie partie. Je crains que des gens ne trouve ce passage chiant et quitte l'article sans aller plus loin. C'est pour moi le point noir du contenu.
  • Tu parles très tôt de reference capabilities, mais tu n'expliques que tard ce que c'est. Et tu n'expliques jamais ce que sont les races conditions. Remonter une partie des explications permettrait de plus d'alléger la partie sur les reference capabilities, qui est assez complexes (ce qui je pense est inévitable vu ce dont tu parles).

C'est globalement un bel article. :)


Impressions au fil de l'eau (faite au fur et à mesure de la lecture) :

L'implémentation de référence du langage est compilée et fonctionne actuellement sur x86 et ARM.

Dans la nomenclature linuxienne typique x86 désigne parfois les systèmes 32 bits, et ARM désigne toujours les systèmes 32 bits. Je suppose que des binaires sont proposés pour un x86_64 (x86 64 bits, parfois appelés amd64), et peut-être même pour AArch-64 (ARM 64 bits). Peut-être util de tourner cette phrase autrement.

Le langage est le fruit du projet de doctorat de Sylvan Clebsch. Il a commencé à travailler sur les concepts derrière Pony en 2011 et le langage est open-source depuis 2015. C'est donc un langage très jeune, mais avec de réelles fondations scientifiques. Les plus grandes inspirations de Pony ont été les travaux sur les acteurs (par Carl Hewitt à l'origine) et sur la sécurité capability-based (par Mark Miller à l'origine). La thèse de S. Clebsch, bien qu'actuellement non finalisée, est disponible sur Github.

Désolé de faire mon chieur, mais j'aime pas ce paragraphe. Dire que le langage a des « fondations scientifiques » n'a pas grand sens. « Issus de récents travaux de la recherche académique » serait nettement plus concret (si c'est bien ça l'idée). Dire C'est la Science, c'est souvent un bon moyen de dire des sottises en affirmant qu'on n'est pas contestable. Je suis persuadé que tu peux dire ce que tu veux dire avec cette phrase de manière bien plus claire et propre. Rien que « basé sur des travaux scientifiques » serait beaucoup mieux à mon avis (avec un lien vers les travaux publiés bien évidemment ^^ ).

Pour la thèse pas fini, ça me fait plus peur qu'autre chose. On a l'impression qu'il l'a commencé en 2011 et toujours pas fini (j'espère que c'est pas ça).

Par un mélange de curiosité et de rigueur scientifique, j'aurai aimé un lien vers les travaux quand tu les cites (un simple lien vers l'article de référence suffirait).

Pas de data races, avec une vérification complète à la compilation via un système nommé reference capabilities ;

J'ai pas compris. :-° Faut dire que je ne sais ni ce qu'est une data races, si un système de références capabilites. Et on n'est qu'au 4e paragraphe…

d'exhaustion

Méthode de calcul ou de vérification d'une grandeur consistant en une suite d'approximations de plus en plus précises. Démontrer par exhaustion.

Méthode d'analyse consistant à énumérer tous les cas possibles, toutes les hypothèses contenues dans une question.

CNRTL

T'es sûr que c'est ce mot que tu voulais utiliser ?

Pony est un langage à acteurs. Un acteur est assez similaire à un objet mais dispose de propriétés supplémentaires très intéressantes. […]

À la fin de la partie, tu n'as pas dit quelles étaient les propriétés qui différenciait les acteurs des objets. De ce que j'ai compris, toute la spécificité est contenu dans les behaviours. De fait, c'est quoi un acteur, sinon un objet qui peut contenir un behaviour ?

En plus des acteurs, Pony dispose de classes, celles-ci étant introduites sans surprise par le mot-clé class.

Stop ! Les acteurs sont proches des objets, les classes sont proches des objets. Dis-nous tout de suite ce qui différencie les deux ! Ne pars pas sur un exemple sans nous dire où tu vas avant.

Idem pour les interfaces et les traits. Après avoir lu ton texte, je dirai bien qu'ils sont identiques, et non pas seulement similaires.

J'ai sauté les types. Je ne sais pas où tu vas et ce que tu veux me montrer. Je me reconcentre et repart sur la partie suivante.

la précédence des opérateurs n'existe pas et il faut placer des parenthèses dans toutes les expressions à plus de deux opérateurs.

Tu es bien en train de dire qu'il faut faire (a * b) + c, voir (a * b) / c pour que le programme compile ? o_O

Filtrage de motifs

Pour avoir fait un peu d'OCaml, je me demandais ce que me dis le compilateur en cas de filtrage incomplet. Par exemple,

1
2
3
4
5
let x: (String | None) = get_x()

match x
| None => foo()
| "abc" => bar()

Pour les références, je trouve ça compliqué mais j'ai à peu près compris, ce qui tient de l'exploit vu le machin. :-°

Pour les performances, y a-t-il des tests un peu standard de fait ? Un truc comme ça.

Il y a deux langages récents qui se veulent concurrents (ou parallèle, il faut que je lise l'article de Nohar) et qui sont récents : Rust et Go. Comment Pony se place-t-il face à eux ?


Conclusion

Bref, un bel article, qui manque peut-être encore un peu de clarté par endroit (tout du moins pour les gens qui comme moi, n'ont vu le parallélisme que de loin). Merci. :)


  1. J'ai déjà eu des gens qui ont (malheureusement) très mal pris un retour de béta, donc je préfère être parfaitement clair.  

+0 -0

Le passage sur les types est lourd, long, et on ne sait pas où on va. C'est d'autant plus gênant que c'est la première vraie partie. Je crains que des gens ne trouve ce passage chiant et quitte l'article sans aller plus loin. C'est pour moi le point noir du contenu.

Je verrai comment alléger.

Tu parles très tôt de reference capabilities, mais tu n'expliques que tard ce que c'est. Et tu n'expliques jamais ce que sont les races conditions. Remonter une partie des explications permettrait de plus d'alléger la partie sur les reference capabilities, qui est assez complexes (ce qui je pense est inévitable vu ce dont tu parles).

Je vais ajouter une explication sur les race conditions. Pour les reference capabilities, je verrai si je peux diluer les explications dans l'article.

L'implémentation de référence du langage est compilée et fonctionne actuellement sur x86 et ARM.

Dans la nomenclature linuxienne typique x86 désigne parfois les systèmes 32 bits, et ARM désigne toujours les systèmes 32 bits. Je suppose que des binaires sont proposés pour un x86_64 (x86 64 bits, parfois appelés amd64), et peut-être même pour AArch-64 (ARM 64 bits). Peut-être util de tourner cette phrase autrement.

Les versions précompilées ne sont disponibles que pour x86 32 et 64 bits, mais la compilation manuelle est également possible sur ARM 32 et 64 bits. Je vais préciser dans l'article.

Le langage est le fruit du projet de doctorat de Sylvan Clebsch. Il a commencé à travailler sur les concepts derrière Pony en 2011 et le langage est open-source depuis 2015. C'est donc un langage très jeune, mais avec de réelles fondations scientifiques. Les plus grandes inspirations de Pony ont été les travaux sur les acteurs (par Carl Hewitt à l'origine) et sur la sécurité capability-based (par Mark Miller à l'origine). La thèse de S. Clebsch, bien qu'actuellement non finalisée, est disponible sur Github.

Désolé de faire mon chieur, mais j'aime pas ce paragraphe. Dire que le langage a des « fondations scientifiques » n'a pas grand sens. « Issus de récents travaux de la recherche académique » serait nettement plus concret (si c'est bien ça l'idée). Dire C'est la Science, c'est souvent un bon moyen de dire des sottises en affirmant qu'on n'est pas contestable. Je suis persuadé que tu peux dire ce que tu veux dire avec cette phrase de manière bien plus claire et propre. Rien que « basé sur des travaux scientifiques » serait beaucoup mieux à mon avis (avec un lien vers les travaux publiés bien évidemment ^^ ).

Je prends note.

Pour la thèse pas fini, ça me fait plus peur qu'autre chose. On a l'impression qu'il l'a commencé en 2011 et toujours pas fini (j'espère que c'est pas ça).

C'est bien ça. Pour plus de contexte, il est en phase de finalisation et il avait toujours un boulot à côté pendant la majeure partie de son doctorat. Je ne sais pas si c'est vraiment utile de détailler ce point dans l'article.

Par un mélange de curiosité et de rigueur scientifique, j'aurai aimé un lien vers les travaux quand tu les cites (un simple lien vers l'article de référence suffirait).

J'ajouterai ça.

Pas de data races, avec une vérification complète à la compilation via un système nommé reference capabilities ;

J'ai pas compris. :-° Faut dire que je ne sais ni ce qu'est une data races, si un système de références capabilites. Et on n'est qu'au 4e paragraphe…

Je pense que j'ajouterai un préambule sur la programmation concurrente en général.

d'exhaustion

Méthode de calcul ou de vérification d'une grandeur consistant en une suite d'approximations de plus en plus précises. Démontrer par exhaustion.

Méthode d'analyse consistant à énumérer tous les cas possibles, toutes les hypothèses contenues dans une question.

CNRTL

T'es sûr que c'est ce mot que tu voulais utiliser ?

Je vérifierai.

Pony est un langage à acteurs. Un acteur est assez similaire à un objet mais dispose de propriétés supplémentaires très intéressantes. […]

À la fin de la partie, tu n'as pas dit quelles étaient les propriétés qui différenciait les acteurs des objets. De ce que j'ai compris, toute la spécificité est contenu dans les behaviours. De fait, c'est quoi un acteur, sinon un objet qui peut contenir un behaviour ?

C'est exactement ça.

En plus des acteurs, Pony dispose de classes, celles-ci étant introduites sans surprise par le mot-clé class.

Stop ! Les acteurs sont proches des objets, les classes sont proches des objets. Dis-nous tout de suite ce qui différencie les deux ! Ne pars pas sur un exemple sans nous dire où tu vas avant.

Je pense que la confusion sur ce point et sur le précédent vient de la distinction classe/objet pour modèle/instance, alors que j'utilise acteur pour désigner à la fois le modèle et l'instance. Je vais voir comment reformuler.

Idem pour les interfaces et les traits. Après avoir lu ton texte, je dirai bien qu'ils sont identiques, et non pas seulement similaires.

La grosse différence c'est qu'une interface introduit un sous-typage implicite alors qu'un trait introduit un sous-typage explicite. Par exemple, avec une interface, on peut avoir des types d'une bibliothèque externe en sous-type, mais pas avec un trait vu que le sous-typage doit être déclaré explicitement. En gros, on choisira l'un ou l'autre en fonction de si l'on veut être flexible et accepter n'importe quel type qui satisfait l'interface, ou si l'on veut éviter le sous-typage accidentel et n'accepter que les types définis comme sous-types.

Je vais plus détailler.

J'ai sauté les types. Je ne sais pas où tu vas et ce que tu veux me montrer. Je me reconcentre et repart sur la partie suivante.

L'objectif de cette partie est de montrer à quoi ressemble le système de types dans sa globalité. Peut être qu'il faudrait que je m'attarde moins sur les éléments individuels ?

la précédence des opérateurs n'existe pas et il faut placer des parenthèses dans toutes les expressions à plus de deux opérateurs.

Tu es bien en train de dire qu'il faut faire (a * b) + c, voir (a * b) / c pour que le programme compile ? o_O

Oui. Ça peut paraître lourd au début mais on s'y habitue.

Filtrage de motifs

Pour avoir fait un peu d'OCaml, je me demandais ce que me dis le compilateur en cas de filtrage incomplet. Par exemple,

1
2
3
4
5
let x: (String | None) = get_x()

match x
| None => foo()
| "abc" => bar()

Actuellement, une branche else renvoyant None est toujours ajoutée. À l'avenir, il est prévu de détecter les filtrages complets pour éviter d'ajouter le else.

Pour les références, je trouve ça compliqué mais j'ai à peu près compris, ce qui tient de l'exploit vu le machin. :-°

Oui, c'est pas évident au début. On n'a pas encore trouvé la manière idéale pour expliquer tout ça. Apparemment les gens visualisent mieux le truc expliqué en terme d'alias autorisés plutôt qu'interdits mais ça reste difficile. En moyenne il faut une semaine ou deux de pratique pour bien assimiler le truc.

Pour les performances, y a-t-il des tests un peu standard de fait ? Un truc comme ça.

Non, tous les benchmarks dont j'ai connaissance sont faits maison (mais avec le code disponible). En effet, il faudrait qu'on ajoute des trucs pour Pony sur ce genre de sites.

Il y a deux langages récents qui se veulent concurrents (ou parallèle, il faut que je lise l'article de Nohar) et qui sont récents : Rust et Go. Comment Pony se place-t-il face à eux ?

Pour Rust, je ne pense pas que ça soit comparable, les problématiques visées sont différentes. Je vois Rust comme un « super C », des performances comparables, des threads nus, des garanties de sûreté et un accès direct aux machineries dangereuses si besoin. Je n'ai pas l'impression que Rust vise la concurrence massive, un programme basé uniquement sur des threads ne scale pas. Il faudrait implémenter un système d'acteurs ou de coroutines au dessus pour obtenir les mêmes possibilités qu'en Pony (d'ailleurs, je pense que le runtime Pony est implémentable en Rust). Au niveau des garanties, les deux langages rendent les data races impossibles, Pony avec uniquement son système de types et Rust avec son système de types et un mécanisme de comptage de références (donc avec un léger surcoût à l'exécution).

Pour Go, la différence se situe dans la manière d'approcher la concurrence. Si l'on prend les exemples de cet article, Go serait un langage entièrement bleu, avec uniquement des opérations bloquantes, et Pony serait un langage entièrement rouge et non bloquant. La manière de programmer est donc très différente. Le meilleur paradigme dépendra probablement du problème à résoudre mais mon avis général sur les channels est à peu près aligné avec cet article. De plus, Go peut subir des data races.

J'ajouterai un passage là dessus dans l'article.

Conclusion

Bref, un bel article, qui manque peut-être encore un peu de clarté par endroit (tout du moins pour les gens qui comme moi, n'ont vu le parallélisme que de loin). Merci. :)

Gabbro

Merci pour tes retours.

+1 -0

Bonjour.

La bêta a été mise à jour.

  • Ajout d'un préambule sur la programmation concurrente ;
  • Allégement de la section sur les types et ajout de plus d'exemples de cas d'utilisation ;
  • Étoffement de la section sur les reference capabilites avec une introduction sur les capabilities en général ;
  • Plusieurs modifications mineures.

Merci d'avance pour vos commentaires.

+0 -0
Ce sujet est verrouillé.