2006/08/12

Pattern-matching e o visitor pattern

Trabalhando diariamente com C++, sendo praticamente um zero à esquerda em orientação a objeto e à engenharia de software da mesma (por opção), comecei a procurar um pouco mais sobre o paradigma, para encontrar recursos que espelhassem algumas funcionalidades que encontro em Objective Caml, especialmente uma: pattern-matching.

Depois de alguma procura, encontrei este artigo, que faz uma comparação direta entre C++, O'Caml, algumas implementações de SML, e outras linguagens, citando justamente o pattern-matching de O'Caml como uma de suas vantagens. Nesta comparação, traz-se a análoga ao pattern-matching no mundo OO, que em outro artigo descobri ser uma técnica de engenharia de software chamada visitor pattern.

Este outro artigo, do criador da linguagem Scala, vem em defesa do pattern matching, trazendo inclusive críticas que são feitas a este recurso, entre elas, que é desnecessário, que quebra o encapsulamento do código, e que não é extensível.

Depois de ler sobre estas informações, fui no artigo da Wikipédia e vi o exemplo da técnica, feito em linguagem Java. Percebi que as críticas que são feitas sobre pattern matching, na verdade, são críticas que muito bem poderiam ser feitas sobre o visitor pattern. Para começar, você precisa criar vários objetos só para tratar os casos possíveis. Um exemplo de 4 casos chega a dar dezenas de linhas de código, enquanto que em O'Caml, você tem uma linha para cada case, em exemplos simples com esse.

Outro ponto importante é a maneira que se utilizam as duas técnicas: no caso do pattern-matching, este é usado dentro de módulos, isolado do programa principal, ou até mesmo no próprio programa principal, mas como um meio de organizar dados obtidos por entrada e os dados de módulos: não há problema de flexilidade nem de extensibilidade, e a técnica se ajusta muito bem para este uso. Também é interessante notar que você não pode realmente usar um pattern no caso do visitor pattern: o compilador faz uma comparação apenas baseando-se no tipo dos objetos, e não é possível usar valores concretos: strings, caracteres e inteiros ficam de fora, o que já limita bastante a técnica em comparação com a primeira.

Por último, mas não menos importante: pelo fato de precisar de chamadas de métodos extra e criar uma dependência desnecessária entre classes, pode-se perceber que quem quebra o encapsulamento na verdade é o visitor pattern, que faz com que o programador precise de muito código só para conseguir um recurso simples. Como já disse o próprio criador da linguagem Scala, as críticas feitas ao pattern matching normalmente originam de quem não entendeu como funciona o recurso. O que faz muito sentido se o problema for observado do ponto de vista prático: os programadores que utilizam orientação a objetos, especialmente aqueles que só utilizam uma única linguagem monoparadigma, raramente conhecem o suficiente a programação funcional moderna para entendê-la, e perdem muitas das vantagens associadas a ela.

E é isso.