Où en est la proposition de l'opérateur Pipeline (|>) ?
Cette page a été traduite par PageTurner AI (bêta). Non approuvée officiellement par le projet. Vous avez trouvé une erreur ? Signaler un problème →
Avec la sortie de babel@7.0.0-beta52, nous avons introduit un nouveau flag de configuration obligatoire pour @babel/plugin-proposal-pipeline-operator, un changement cassant pour l'opérateur pipeline. Pour dissiper toute confusion, examinons la proposition de pipeline et la raison pour laquelle nous avons dû introduire cette option de configuration.
État actuel
L'opérateur pipeline a été initialement introduit par Gilbert Garza, offrant une syntaxe élégante pour « simplifier les chaînages d'appels de fonctions de manière lisible et fonctionnelle ». L'opérateur pipeline trouve ses origines dans plusieurs langages, dont F#, Hack, Elm, Elixir et d'autres, mais deux points de controverse majeurs sont apparus lors de son introduction dans JavaScript :
-
S'il faut ou non introduire des placeholders, et comment le faire
-
Comment gérer async / await dans le pipeline
Les placeholders
La première question concernait les placeholders. Celle-ci a été soulevée par Kevin Smith dans cette issue, où il a suggéré un pipelining de style Hack. Dans Hack, un placeholder est requis pour chaque étape droite du pipeline, comme dans cet exemple :
namespace Hack\UserDocumentation\Operators\Pipe\Examples\MapFilterCountPiped;
function piped_example(array<int> $arr): int {
return $arr
|> \array_map($x ==> $x * $x, $$)
|> \array_filter($$, $x ==> $x % 2 == 0)
|> \count($$);
}
var_dump(piped_example(range(1, 10)));
Nous avons développé ce concept, car un placeholder peut facilement être utilisé dans des expressions arbitraires, le placeholder représentant la valeur renvoyée par l'étape précédente. Cela offre une flexibilité et une puissance supplémentaires au sein d'une étape de pipeline.
L'inconvénient réside dans la complexité liée à l'introduction d'un nouveau jeton. Le dièse (#) est le choix actuel, et bien que cela soit encore sujet à débat, tout jeton aurait potentiellement plusieurs significations. Le dièse est également utilisé par la proposition des champs privés, et toutes les autres options sont déjà utilisées d'une manière ou d'une autre.
Async / Await
L'introduction initiale du pipeline incluait cette syntaxe pour await :
x |> await f
qui se désucrerait en
await f(x)
Malheureusement, les utilisateurs pourraient s'attendre à ce désucrage alternatif :
(await f)(x)
Bien qu'il y ait eu des réticences sur l'idée d'inclure la gestion asynchrone dans le pipeline, les membres du comité ont exprimé des inquiétudes quant à un opérateur pipeline qui ne gérerait pas async/await. Bien qu'il existe des moyens de gérer les fonctions renvoyant des Promises sans syntaxe explicite, ceux-ci sont trop lourds pour être utiles ou nécessitent une fonction d'aide.
Solutions proposées
Suite à ces discussions, deux propositions, ainsi qu'une proposition minimale de base, ont émergé pour les résoudre : les Pipelines F# et les Pipelines Intelligents. Voyons comment elles résolvent les problèmes posés ci-dessus.
Pipelines Minimaux
Cette proposition couvre les fonctionnalités de base de l'opérateur pipeline. La proposition minimale interdit await, donc aucune gestion asynchrone n'est impliquée, et n'inclut aucun placeholder. Elle correspond au comportement du plugin babel avant que nous introduisions la configuration et est la spécification actuelle dans le dépôt de la proposition de l'opérateur pipeline. Elle fonctionne davantage comme un épouvantail, pour comparer les avantages et compromis des autres propositions, et il est peu probable qu'elle soit acceptée en l'état sans défauts rédhibitoires dans les deux alternatives.
Pipelines F#
Sur la question des placeholders, les Pipelines F# soutiennent qu'ils ne sont pas nécessaires. Dans la proposition de base, les fonctions fléchées remplissent le rôle des placeholders, nécessitant moins de nouvelle syntaxe et s'appuyant sur une syntaxe que les développeurs connaissent déjà et utilisent depuis ES2015.
Dans la spécification actuelle, les fonctions fléchées doivent être entourées de parenthèses :
let person = { score: 25 };
let newScore = person.score
|> double
|> (_ => add(7, _))
|> (_ => boundScore(0, 100, _));
Des explorations sont en cours pour déterminer s'il serait possible d'utiliser les fonctions fléchées sans parenthèses, car elles représentent un fardeau syntaxique important.
Concernant la gestion de l'asynchrone, les pipelines F# traitent await de manière similaire à une fonction unaire :
promise |> await
Cela se désucrerait en :
await promise
et peut donc être utilisé au milieu de chaînes de fonctions plus complexes avec de l'asynchrone :
promise
|> await
|> (x => doubleSay(x, ', '))
|> capitalize
|> (x => x + '!')
|> (x => new User.Message(x))
|> (x => stream.write(x))
|> await
|> console.log;
Le traitement spécial de await pourrait potentiellement permettre à d'autres opérateurs unaires d'être utilisés de la même manière (par exemple typeof), mais les pipelines F# ne les prennent pas en charge initialement.
Smart Pipelines
Les Smart Pipelines poussent le concept de placeholder à sa conclusion logique, permettant de gérer l'application partielle ainsi que des expressions arbitraires dans un pipeline. La longue chaîne précédente s'écrirait ainsi :
promise
|> await #
|> doubleSay(#, ', ')
|> # || throw new TypeError()
|> capitalize
|> # + '!'
|> new User.Message(#)
|> await stream.write(#)
|> console.log;
Les pipelines intelligents ont quelques règles pour l'espace réservé. Si un identifiant nu est fourni à une étape du pipeline, aucun jeton n'est nécessaire, appelé « style nu » :
x |> a;
x |> f.b;
Contrairement à Hack, les fonctions unaires ne nécessitent pas de token de placeholder.
Pour les autres expressions, un placeholder (appelé "lexical topic token") est requis, et le code lèvera une SyntaxError anticipée s'il n'est pas inclus en "topic style" :
10 |> # + 1;
promise |> await #;
S'il y a des opérateurs, des parenthèses (y compris pour les appels de méthode), des crochets, ou quoi que ce soit d'autre que des identifiants et des séparateurs par points, alors un token de topic est nécessaire. Cela évite les pièges et supprime les ambiguïtés lorsqu'aucun token de topic n'est utilisé.
Les Smart Pipelines résolvent ainsi le problème de l'asynchrone de manière intégrative, permettant d'intégrer toutes les expressions possibles dans un pipeline ; non seulement await, mais aussi typeof, yield, et tout autre opérateur souhaité.
Le rôle de Babel
Une fois les trois propositions détaillées, nous avons réalisé que la discussion et le débat ne permettraient probablement pas de résoudre les tensions inhérentes entre elles. Nous avons décidé que la meilleure façon de prendre une décision serait d'obtenir le retour des développeurs en utilisant les propositions dans du code réel. Compte tenu du rôle de Babel dans la communauté, nous avons décidé d'intégrer les trois propositions dans le plugin de l'opérateur pipeline.
Comme ces propositions s'analysent légèrement différemment, un support doit être ajouté à @babel/parser (anciennement babylon), et l'analyseur doit être configuré en fonction de la proposition ciblée. Le plugin de l'opérateur pipeline nécessite donc l'option "proposal", à la fois pour configurer babylon et sa propre transformation.
Nous travaillions sur un calendrier serré, car nous devions introduire les changements cassants dans babel, @babel/parser ainsi que le plugin de proposition de pipeline avant que babel@7 ne quitte la version bêta. Nous voulions également que le plugin puisse finalement adopter par défaut la proposition acceptée, rendant ainsi l'option de configuration obsolète.
Compte tenu de ces deux contraintes, nous avons opté pour l'introduction de cette nouvelle option de configuration et l'avons rendue obligatoire, forçant les utilisateurs à choisir la proposition qu'ils souhaitent utiliser dans leur projet. Une fois qu'une proposition particulière sera acceptée comme comportement canonique de l'opérateur pipeline, nous déprécierons l'option "proposal" et adopterons par défaut celle qui est acceptée, tandis que les propositions rejetées seront supprimées dans la prochaine version majeure.
Participer
Si vous souhaitez vous impliquer dans la proposition de l'opérateur pipeline, toutes les discussions sont publiques et accessibles dans le dépôt de l'opérateur pipeline. Vous pouvez également consulter la présentation de la dernière réunion du TC39. Enfin, vous pouvez contacter James DiGioia, J. S. Choi ou Daniel Ehrenberg sur Twitter.
Mais surtout, une fois le travail finalisé, testez l'opérateur pipeline dans vos propres projets ! Nous travaillons également à intégrer des options dans le REPL pour vous permettre d'expérimenter le code directement. Vos retours et exemples concrets sont essentiels pour rendre cette fonctionnalité utile, donc nous attendons vos impressions avec impatience. Tweetez-nous à @babeljs pour nous faire part de votre expérience.