Aggiornamenti sulla Proposta dell'Operatore Pipeline (|>)
Questa pagina è stata tradotta da PageTurner AI (beta). Non ufficialmente approvata dal progetto. Hai trovato un errore? Segnala problema →
Con il rilascio di babel@7.0.0-beta52, abbiamo introdotto un nuovo flag di configurazione obbligatorio per @babel/plugin-proposal-pipeline-operator, una modifica sostanziale per l'operatore pipeline. Per chiarire ogni dubbio, esaminiamo la proposta e le ragioni che hanno reso necessaria questa opzione di configurazione.
Stato Attuale
L'operatore pipeline fu originariamente proposto da Gilbert Garza per fornire una sintassi elegante che "ottimizzasse le chiamate a funzione concatenate in modo leggibile e funzionale". Presenta radici in linguaggi come F#, Hack, Elm ed Elixir, ma due punti critici hanno caratterizzato il dibattito sulla sua introduzione in JavaScript:
-
Se e come introdurre i segnaposto (placeholder)
-
La gestione di async/await nelle pipeline
Segnaposto (Placeholder)
Il primo punto riguardava i segnaposto. La questione fu sollevata da Kevin Smith in questo issue, dove propose lo stile Hack. In Hack, ogni passaggio a destra della pipeline richiede un segnaposto, come in questo esempio:
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)));
Abbiamo sviluppato questo concetto poiché un segnaposto può essere utilizzato in espressioni arbitrarie, rappresentando il valore restituito dal passaggio precedente. Ciò garantisce maggiore flessibilità e potenza all'interno di ogni fase della pipeline.
Lo svantaggio risiede nella complessità dell'introdurre un nuovo token. Il cancelletto (#) è l'opzione attuale, e sebbene sia ancora soggetto a dibattiti ("bikeshedding"), qualsiasi token potrebbe assumere significati multipli. Il cancelletto è già utilizzato dalla proposta sui campi privati, e tutte le alternative sono già impiegate in qualche forma.
Async / Await
La versione iniziale della pipeline includeva questa sintassi per await:
x |> await f
che si sarebbe desugarata in
await f(x)
Tuttavia, gli utenti potrebbero aspettarsi questa desugarizzazione alternativa:
(await f)(x)
Nonostante perplessità sull'inclusione della gestione asincrona, i membri del comitato hanno espresso preoccupazioni riguardo a un operatore pipeline che non supportasse async/await. Sebbene esistano modi per gestire funzioni che restituiscono Promise senza sintassi esplicita, risultano troppo macchinosi o richiedono funzioni helper.
Soluzioni Proposte
Da questi dibattiti sono emerse due proposte, affiancate da una versione minima di base: Pipeline F# e Pipeline Intelligenti. Analizziamo come affrontano i problemi menzionati.
Pipeline Minime
Questa proposta copre la funzionalità base dell'operatore. Vieta l'uso di await, escludendo completamente la gestione asincrona, e non include segnaposto. Corrisponde al comportamento del plugin Babel prima dell'introduzione della configurazione ed è l'attuale specifica nel repository della proposta. Funge principalmente da "straw man" per confrontare vantaggi e compromessi delle altre proposte, ed è improbabile che venga accettata così com'è senza difetti fatali nelle alternative.
Pipeline F#
Sulla questione dei segnaposto, le Pipeline F# sostengono che non siano necessari. Nella proposta base, le arrow function sostituiscono i segnaposto, richiedendo meno sintassi nuova e basandosi su costrutti familiari agli sviluppatori sin da ES2015.
Come attualmente specificato, le funzioni freccia devono essere racchiuse tra parentesi:
let person = { score: 25 };
let newScore = person.score
|> double
|> (_ => add(7, _))
|> (_ => boundScore(0, 100, _));
Sono in corso esplorazioni per determinare se sia fattibile consentire l'uso di funzioni freccia senza parentesi, poiché rappresentano un onere sintattico significativo.
Per quanto riguarda l'async, le pipeline F# trattano await in modo simile a una funzione unaria:
promise |> await
Questo verrebbe trasformato in:
await promise
e può quindi essere utilizzato nel mezzo di catene di funzioni più complesse con async:
promise
|> await
|> (x => doubleSay(x, ', '))
|> capitalize
|> (x => x + '!')
|> (x => new User.Message(x))
|> (x => stream.write(x))
|> await
|> console.log;
Il trattamento speciale di await potrebbe potenzialmente abilitare altri operatori unari in modo simile (es. typeof), ma le pipeline F# non li supportano inizialmente.
Smart Pipelines
Le Smart Pipelines portano l'idea del segnaposto alla sua logica conclusione, consentendo di gestire sia l'applicazione parziale che espressioni arbitrarie in una pipeline. La lunga catena precedente verrebbe scritta così:
promise
|> await #
|> doubleSay(#, ', ')
|> # || throw new TypeError()
|> capitalize
|> # + '!'
|> new User.Message(#)
|> await stream.write(#)
|> console.log;
Le Smart Pipelines hanno alcune regole per il segnaposto. Se viene fornito un identificatore semplice a un passaggio della pipeline, non è necessario alcun token, nello stile chiamato "bare style":
x |> a;
x |> f.b;
A differenza di Hack, le funzioni unarie non richiedono un token segnaposto.
Per altre espressioni, è richiesto un segnaposto (chiamato "lexical topic token") e il codice genererà un SyntaxError anticipato se non incluso nello stile "topic style":
10 |> # + 1;
promise |> await #;
Se sono presenti operatori, parentesi (inclusi per le chiamate di metodo), parentesi quadre o qualsiasi elemento diverso da identificatori e separatori punto, è necessario un token topic. Questo evita problemi (footguns) ed elimina ambiguità quando non si utilizza un token topic.
Le Smart Pipelines risolvono quindi la questione dell'async in modo integrato, consentendo di incorporare in una pipeline qualsiasi espressione possibile; non solo await, ma anche typeof, yield e qualsiasi altro operatore desiderato.
Il ruolo di Babel
Dopo aver sviluppato tutte e tre le proposte, ci siamo resi conto che discussioni e dibattiti difficilmente avrebbero risolto le tensioni intrinseche tra di esse. Abbiamo deciso che il modo migliore per prendere una decisione sarebbe stato attraverso il feedback degli sviluppatori, usando le proposte nel codice reale. Dato il ruolo di Babel nella comunità, abbiamo deciso di introdurre tutte e tre le proposte nel plugin dell'operatore pipeline.
Poiché queste proposte analizzano la sintassi in modo leggermente diverso, è necessario aggiungere supporto a @babel/parser (precedentemente babylon), e il parser deve essere configurato in base alla proposta attualmente analizzata. Il plugin stesso dell'operatore pipeline richiede quindi l'opzione "proposal", sia per configurare babylon che per la propria trasformazione.
Abbiamo lavorato con tempistiche ristrette poiché dovevamo introdurre eventuali modifiche di rottura in babel, @babel/parser e nel plugin della proposta pipeline prima che babel@7 uscisse dalla beta. Volevamo inoltre che il plugin potesse impostare come predefinita la proposta eventualmente accettata, rendendo così obsoleta l'opzione di configurazione.
Date queste due esigenze, abbiamo optato per introdurre questa nuova opzione di configurazione rendendola obbligatoria, forzando gli utenti a scegliere quale proposta usare nel loro progetto. Una volta che una proposta specifica verrà accettata come comportamento canonico dell'operatore pipeline, deprecheremo l'opzione "proposal" e imposteremo come predefinita quella accettata, mentre le proposte scartate verranno rimosse nella successiva versione major.
Partecipa
Se sei interessato a partecipare alla proposta per l'operatore pipeline, tutte le discussioni sono pubbliche e le puoi trovare nel repository dell'operatore pipeline. Puoi anche consultare la presentazione dell'ultimo incontro TC39. Infine, puoi contattare James DiGioia, J. S. Choi o Daniel Ehrenberg su Twitter.
Ma soprattutto, una volta completato il lavoro, sperimenta l'operatore pipeline nei tuoi progetti! Stiamo anche lavorando per aggiungere opzioni al repl, così potrai testare il codice anche lì. Abbiamo bisogno di feedback e codice reale per rendere questa funzionalità utile, quindi ci piacerebbe conoscere la tua esperienza. Scrivici su Twitter a @babeljs per farci sapere.