<div dir="ltr"><div><div><div>Smart-matching é uma feature que surgiu na versão 10.0 do Perl 5, baseado em seu equivalente do Perl 6:<br><br><a href="http://perlcabal.org/syn/S03.html#Smart_matching">http://perlcabal.org/syn/S03.html#Smart_matching</a><br>
<br>A idéia é simples: fazer a coisa certa ao compararmos 2 valores, sem precisar ficar perdendo tempo formatando um deles para se adequar ao outro. Em termos práticos, isso quer dizer que, se o item do lado direito da operação "aceitar" o item do lado esquerdo, a operação é avaliada como verdadeira. Senão, falsa. Por exemplo:<br>
<br>   my $x = 3;<br><br>   $x ~~ 3     # verdadeiro!<br>   $x ~~ 3.0  # verdadeiro!<br>   $x ~~ "3"   # verdadeiro!<br>   $x ~~ "   +3.000    "  # verdadeiro!<br>   $x ~~ "3D" # falso<br><br>
O operador de smartmatch também é útil para saber se um item faz parte de uma coleção:<br><br>  $x ~~ ( 1, 18, undef, 3 )  # verdadeiro!<br><br>Legal, né? De fato, lê-se "~~" como "em" (do inglês "in").<br>
<br>Então, qual é o problema?<br><br>O problema é que existem vários tipos de estruturas de dados em Perl e, consequentemente, várias combinações possíveis para smartmatching. Pra piorar a situação, a definição de "a coisa certa" a ser feita num smartmatching varia muito de pessoa para pessoa, tanto que hoje é praticamente impossível usar o ~~ para algo além de strings simples sem olhar a tabela de equivalência dele na documentação - que diga-se de passagem tem 288 linhas densas com regras, exceções e detalhes de uso.<br>
<br>O smartmatch tentou ser esperto demais, e isso acabou confundindo seus usuários.<br><br>A primeira mudança aconteceu cedo, do 10.0 para o 10.1, quando o smartmatch deixou de ser comutativo e passou a depender principalmente do tipo de dado do lado direito da operação, entre outros pequenos ajustes.<br>
<br>Ainda assim, alguns comportamentos eram bem estranhos. Por exemplo, no 5.10.1, "undef ~~ 0" era avaliado como verdadeiro, assim como 'undef ~~ ""'. Isso acontecia porque undef era transformado em 0 e em "" por coerção. No entanto, a coerção não acontecia em todos os casos. Por exemplo, "undef ~~ [0]" era falso!<br>
<br>De lá pra cá, casos como esse geraram tanta discussão sobre qual seria o comportamento correto do smartmatch que muitas mudanças foram (e continuam sendo) feitas. Hoje o ~~ é controlado por uma dispatch table massiva chamada em tempo de execução com mais de 20 rotas recursivas (sim, recursivas) dependendo dos operandos. Você é capaz de dizer, por exemplo, o que acontece, ou o que deveria acontecer, quando fazemos %hash ~~ @array? Quer chutar, sem olhar o "perlop"? Nem eu.<br>
<br>O fato é que o comportamento do smartmatch para itens além do caso comum é tão confuso que mesmo programadores experientes acabam optando por simplesmente deixar pra lá e fingir que o smartmatch não existe. O que é uma pena.<br>
<br>Depois de tantas discussões e mudanças de comportamento ao longo das versões do perl, as funções que dependem do smartmatching (~~, given/when) foram finalmente marcadas explicitamente como experimentais no perlsyn a partir da versão 15.7, embora já tivessem sendo tratadas assim desde sua introdução ao core, justamente por sua natureza extremamente volátil.<br>
<br>Muitos falam sobre tornar o ~~ obsoleto e retirá-lo do core, oferecendo-o na forma de um plugin (<a href="https://github.com/doy/smartmatch">https://github.com/doy/smartmatch</a>, <a href="https://github.com/doy/smartmatch-engine-core">https://github.com/doy/smartmatch-engine-core</a>). Outros argumentam que a retrocompatibilidade precisa ser mantida a qualquer custo, exceto em casos de bugs. O problema dessa abordagem é que, como o smartmatch funciona hoje de forma relativamente subjetiva, a definição do que é um bug e o que não é também se torna subjetiva.<br>
<br>Felizmente, nosso atual Pumpking (e muitos outros desenvolvedores do core) vem propondo uma solução intermediária ao problema, que visa simplificar o smartmatching para que tenha um comportamento bem mais claro, previsível e fácil de lembrar.<br>
<br></div><div>A nova proposta:<br>=============<br></div><div><br></div><div>* Se $a for qualquer coisa e $b for undef, "$a ~~ $b" significaria "$a em undef?" e retorna verdadeiro se e somente se $a não estiver definido. Em idioma Perl, dizer "$a ~~ undef" seria a mesma coisa que " ! defined $a ".<br>
</div><div><br>* Se $a for qualquer coisa e $b for um scalar 
simples (não referência, não glob, não vstring) então "$a ~~ $b" seria 
uma comparação de igualdade.<br><br></div><div>* Se $a for qualquer coisa e $b for um coderef, dizer "$a ~~ $b" significaria "$a em função $b?", ou seja, se o resultado da função $b chamada com $a como parâmetro retorna verdadeiro. Em Perl, seria o mesmo que dizer "$b->($a)".<br>
<br></div><div>* Se $a for qualquer coisa e $b for uma expressão regular, dizer "$a ~~ $b" é o mesmo que "$a em regex $b?", ou seja: $a =~ $b.<br><br></div><div>* Se $a for qualquer coisa e $b for um objeto que faça overload do ~~, dizer "$a ~~ $b" delega a verificação para o overload.<br>
<br></div><div>* Se $a for um objeto que faça overload do ~~ e $b for qualquer coisa, a mesma lógica é usada (só que ao contrário).<br><br></div><div>* Qualquer outra comparação com ~~ gera exceção fatal.<br><br></div><div>
Só isso. Essa proposta, se aceita, vai simplificar imensamente a funcionalidade do smartmatching, bem como a documentação, que hoje é espalhada em diversos exemplos e edge-cases no perlop e no perlsyn.<br></div><br></div>
Essa idéia não vem sozinha, claro, especialmente pq os maiores defensores do smartmatch argumentam sobre as vantagens de um operador "em" para listas. A proposta desse novo smartmatch prevê também a inclusão de funções de junction (junção) dentro do core do Perl 5, especificamente any() e all(), que resolveriam o problema de forma bem mais elegante, já que possibilitariam outras verificações entre listas além do smartmatching.<br>
<br></div><div>Já existe no CPAN uma implementação moderna de junctions em Perl 5:<br><br><a href="https://metacpan.org/module/Syntax::Keyword::Junction">https://metacpan.org/module/Syntax::Keyword::Junction</a><br></div>
<div><div><br>Esse módulo (e seus predecessores) estão servindo como teste de sintaxe e funcionalidade, e se junctions entrarem para o core no futuro é bem possível que assuma um formato muito parecido, senão igual, a esse. Para saber mais sobre junctions, acesse o link acima.<br>
<br>Finalmente, se você curte o conceito de smartmatching, recomendo o módulo do Leon Timmermans, Smart::Match, que propõe uma sintaxe mais explícita para smartmatching dentro de seus programas.<br><br></div>Até lá, use o smartmatching com cuidado :-)<br>
<div><br><br></div><div>[]s<br><br></div><div>-b<br><br><br><div>P.S.: Pra participar mais ativamente da conversa sobre sobre o futuro do smartmatching, assine a lista perl5porters (em inglês). Lembre-se de ler o histórico antes de fazer perguntas, já que o tema já 
foi percorrido muitas vezes, gerando discussões muitas vezes 
acaloradas. Pra facilitar quem quer ficar no modo "somente leitura" do 
tema, o link abaixo mostra todas as mensagens envolvendo smartmatching 
que circularam na p5p:<br><br><a href="http://perl.markmail.org/search/?q=list%3Aorg.perl.perl5-porters+smart+matching">http://perl.markmail.org/search/?q=list%3Aorg.perl.perl5-porters+smart+matching</a><br></div><div><br>
</div></div></div></div>