Pipe operator para Javascript em stage1 no TC39. Ok mas pra que serve mesmo?

Márcio Costa
Juntos Somos Mais
Published in
5 min readOct 30, 2020

Uma breve explicação sobre o assunto.

Foto por @raexler em https://unsplash.com

Se assim como eu você se interessa bastante por programação funcional e é dev Javascript deve estar sabendo que a proposta está em draft no tc39. Se você já manja do assunto e quer ir direto no link, ele está no final do post. Entretanto se você não conhece nadinha de FP e acabou caindo por aqui, espero tornar você um novo convertido ou pelo menos deixar aquela pulga atrás da orelha e curioso sobre o assunto.

Pipe operators não são novidades em linguagens puramente funcionais como F#, Haskell, Elixir, Ocaml etc. Todavia, não é hoje de nosso querido Javascript tem incorporado cada vez mais conceitos de programação funcional (em nome do map, filter, reducer, amém), dito isso, a proposta está a nível de discussão para a implementação nas próximas versões do ECMA.

Beleza, mas que raios é um pipe operator e pra que ele serve?

Bom, a explicação mais simples é:

Dado um valor inicial em uma função f(x), o produto desta é passado como argumento para uma função subsequente f(f(x)) e assim sucessivamente.

Lendo assim parece um problema de álgebra para resolver e isso é normal pra quem ainda não tem intimidade com programação funcional, essa é uma das maiores dificuldades no aprendizado do assunto e toda vida que você pesquisar por isso no google, vai sempre se deparar com exemplos que parecem incompreensíveis e sem aplicabilidade no dia a dia.

Então vamos lá.

Imagine que tenho uma string e com ela quero fazer 3 coisas, duplicar a string, fazer com que a primeira letra seja maiúscula e por fim colocar uma exclamação no final. Logo de cara você pensa em escrever 3 métodos (não vou me ater aos detalhes de implementação de cada um), um pra cada tarefa e utilizá-los para chegar no resultado esperado certo? Ok, nada de novo sob o sol:

Resultado esperado atingido, mas, sempre tem um mas. Podemos executar a mesma operação de forma muito mais elegante e sem precisar criar tantas interdependências. Em um exemplo pequeno como esse não parece nada demais, mas não é difícil se deparar no dia a dia com funções bem mais complexas que vão se chamando umas dentro das outras para chegar a um resultado X. É para simplificar e tornar esse processo mais transparente que o pipe operator funciona:

Wow, que legal, que diferentão! Então, repita comigo: "Dado um valor inicial em uma função, o produto desta é passado como argumento para uma função subsequente e assim sucessivamente."

Agora faz mais sentido? dado um valor inicial: hello esse valor é passado para doubleSay, que vai duplicar a string e jogar seu resultado para capitalize. Ela, por sua vez vai pegar o primeiro h deixá-lo em maiúsculo e aqui você já deve ter pego a idéia.

A má notícia vem agora: essa proposta ainda está em stage1 e pode ser que demore um tempo para ser implementada.

A boa notícia vem agora: com os recursos que temos hoje no javascript, já é possível escrever seu próprio pipe.

Em uma implementação grosseira, poderíamos executar os três métodos encadeados:

Porém, imaginem a dor de cabeça de ter que ficar se preocupando com esse monte de parêntesis caso você precise implementar, sei lá, 7 métodos encadeados… Seria um verdadeiro inferno.

É aí que você pode colocar a caixola pra funcionar, queimar uns neurônios e escrever seu próprio pipe, mas não se preocupe, esse post pode te ajudar.

Vamos começar por criar uma função que recebe funções como argumento e vamos percorrer essas funções usando reduce para ter acesso a cada uma delas:

Boa, agora o que precisamos fazer é executar cada função passando como parâmetro o resultado da função anterior:

por fim, precisamos de um valor inicial (v):

Feito, agora podemos passar um array de funções e um valor inicial pro pipe e voilà!

Poderíamos parar por aqui mas ainda dá pra deixar nosso pipe ainda mais interessante usando rest parameters:

Dessa maneira não precisamos mais do array de funções:

Show de bola, mas vamos deixar nosso pipe ainda mais bacana usando uma closure, isso nos dá a possibilidade de contextualizar (aplicar parcialmente) nosso valor inicial e aplicar as mesmas funções para valores diferentes.

Se você ainda não está familiarizado com closures, dá uma lida aqui e aqui

Eita, entendi nada! Beleza, vamo junto:

Agora nosso pipe recebe n funções que serão guardadas via closure e retorna uma nova função que recebe o valor V e só quando esta segunda for executada, irá aplicar as n funções nesse valor inicial. Parece complicado mas é mais simples do que você pensa:

Agora sim o negócio ficou profissional! mas cuidado, lembre-se que o nosso PipeFunctions é unidirecional e ininterrupto, ou seja, uma vez que um valor entrar nele ele sofrerá todas alterações pelo meio do caminho até chegar do outro lado, então, pense em tudo que você quer fazer com o valor antes de colocá-lo no pipe.

Beleza, agora você ainda deve estar se perguntando no que isso pode ser aplicado no seu dia a dia, para esse problema não existe uma solução simples.

Note, que o pipe não é uma solução mágica e que ele depende da implementação da cada um dos métodos (exclaim, capitalize e doubleSay). É de suma importância que cada um desses métodos sejam funções puras e que não provoquem side-effects por aí, então se você ainda não tem idéia de como usar um pipe em um código, pode ser que ele ainda esteja com lógicas muito emaranhadas umas nas outras, e isso seria assunto pra um ou mais posts.

É isso, espero que você tenha curtido e que a sementinha da programação funcional tenha ficado na sua mente. Deixo abaixo o link completo da proposta:

E também deixo o link de um baita post de um cara que eu sou mega fã que me ajudou bastante a escrever esse post aqui. Além do nosso pipe esse post é cheio de outras implementações magníficas (mas esteja avisado, eu precisei ler umas 4 vezes hahaha):

https://medium.com/javascript-scene/curry-and-function-composition-2c208d774983

--

--