Páginas

Friday, May 27, 2011

Sobre escolhas no projeto de linguagens de programação

Este tópico muito me atrái, e por vezes levanto esta discussão nos nossos encontros semanais do Dojo Rio.

Ontem fiz um post tentando esclarer que num mar de similaridades sintáticas podem existir muitas diferenças semânticas. O caso prático foi uma comparação envolvendo Boo, Python e Ruby.

A discussão seguiu na lista do Dojo, e um outro aspecto que marca a diferença entre escolhas feitas no projeto da linguagem Python e escolhas feitas no projeto da linguagem Boo surgiu num comentário do Juan. Este post é uma reflexão sobre este aspecto.

O Juan disse:
De qualquer forma, a coisa que mais me faz gostar de boo é não escrever "__init__", e sim "constructor".

Taí, gosto é um negócio bem abstrato e indiscutível muitas das vezes.

Seguindo a linha de papos que temos às vezes sobre as escolhas feitas no projeto de linguagens e as consequências que estas escolhas acarretam, ser "__init__" ou "constructor" é mais uma questão de escolha, na qual cabe-nos apenas declarar nosso gosto se o tivermos, e observar consequências.

Talvez por estar acostumado com a filosofia Python, o Zen of Python se quiserem, eu gosto da consistência ortogonal do "__whatever__" como disse o Berrondo.
E falar sobre gosto pára por aqui.


Mas e as consequências das escolhas?

1) Uma delas já está embutida na fala do Berrondo, a questão da consistência.
Neste ponto, uma das algumas vantagens que observo é a facilidade de identificação visual do papel de um método em uma classe:

  • Se ao bater o olho, numa fração de segundos, em um bloco de código e ver "def __algumacoisa__(self, ...):", então trata-se de alguma coisa especial.

2) De certa forma também evita as colisões de nome (name clashes):
  • Convenhamos que é mais natural num código de "usuário" (da linguagem) escrevermos "def meumetodo(self, ...):" do que "def __meumetodo__(self, ...):". Ou seja, "__" foi escolhido de forma a ser um prefixo que em condições normais não seria utilizado (não é como "get" ou "set"). Como se não bastasse, além do prefixo também tem o sufixo "__".
  • Convenhamos ser mais provável inadvertidamente escrevermos "GetHashCode" do que "__hash__" em um método que não tem nada a ver com o papel destes métodos na linguagem.
Podemos argumentar a favor de Boo dizendo que a tipagem estática e o processo de compilação podem detetar inconsistências, mas na prática aparentemente nada impede que sobrescrevamos o método padrão "op_Add" por um nosso que não atenda as espeficicações originais — um erro de semântica quase nunca é detetado de forma automatizada.

Não tenho Boo aqui pra testar. Chutando pelo comportamento de Java, se existir um método herdado "op_Add" e um outro declarado e implementado na classe em questão, e os dois tiverem assinaturas diferentes, o método a ser usado é definido pelos tipos de argumentos recebidos na chamada.

Isto é:
public class Falante {  
  public String toString() {  
    return "Sou um objeto da classe Falante";
  }
  public String toString(String nome) {  
    return "Olá " + nome + ", tudo bem hoje?";
  }
}

...

Falante f = new Falante();
f.toString() /*  Sou um objeto da classe Falante  */ 
f.toString("Túlio") /*  Olá Túlio, tudo bem hoje?  */

3) A terceira consequência que me vem em mente é a questão da extensibilidade. O Berrondo citou que "__whatever__" remetem a protocolos em Python, coisa que se assemelha vagamente ao papel de interfaces em Java (cuidado, não é a mesma coisa!). A sintaxe da forma que é tem uma vantagem de extensibilidade:
  • Você pode criar seu próprio protocolo! E de fato eles existem. Para diversas coisas, como serialização de dados, mocks, e qualquer coisa que você puder imaginar. Uma biblioteca ou framework pode adicionar novos protocolos, os quais você usa para interagir com essa ou esse.
  • É um "duck typing" institucionalizado.
A escolha de Boo já não tem esta vantagem, e não sei qual seria o equivalente dos protocolos. Criam-se classes abstratas, interfaces, o que?! Não sei.

Ah, claro, é preciso deixar claro que não é o fato de você poder criar "seu próprio protocolo" que é excitante, mas sim que o seu protocolo é tão bom quanto os que já vem na linguagem, e inclusive tem a mesma aparência sintática (se você assim dedidir, afinal ao invés de chamar de __meumetodo__ poderia sem sombra de dúvida ter sido chamado de meumetodo).

A grande beleza está na manutenção da consistência ao se expandir a linguagem para atender à sua necessidade.

(Ah, e neste ponto Lisp, na minha opinião, domina. Fique ligado nos meus posts sobre Lisp/Scheme/Racket)


Listei 3 consequências, e aposto que existem outras... você é capaz de citar mais alguma?

Não tenho conhecimento de Boo além do que fizemos na última quarta no dojo, portanto podem haver deslizes - se detetar algum me avise :D

No comments: