Dynamic Typing - Capability versus Contract - Parte 1
Enviado em 3 de Junho de 2008
Publicado por Felipe Rodrigues | Enviar por e-mail
| Hits para esta publicação: 339
Há algum tempo tenho sido um pouco mais que um simples curioso sobre a diferença CONCEITUAL entre as tipagem dinâmicas e estáticas.
Cada vez mais as pessoas tem se interessado por linguagens menos restritivas e com tipagem dinâmica. Esse fenômeno tem sido testemunhado por todos nós quando ouvimos falar sobre Ruby, Groovy, Phyton, ActionScript, JavaScript, Erlang, Lisp, Lua, etc.
Esse fenômeno tem se reforçado com a “novidade” que é o suporte a esse tipo de linguagem nas plataformas mais “robustas” ou pelo menos mais consolidadas no mercado corporativo, como a plataforma Java e .Net. Cada vez mais linguagens são suportadas por essas plataformas que são sinônimos de tecnologia nas empresas. Isso faz com que os desenvolvedores sejam atraídos por novos paradigmas e novas práticas de desenvolvimento extremamente baseados em Metaprogramação.
Metaprogramação significa escrever programas que manipulam programas e isso inclui manipular a si próprio. Imagine o poder de adicionar métodos em um objeto quando você bem entender? Não precisar especificar os tipos de variáveis e também ter a certeza de que tudo no seu código é um objeto, incluindo os métodos. Isso seria bom? Vamos analisar essa questão um pouco mais a fundo.
Em linguagens como Java, C, C++, C# etc., temos a segurança da tipagem estática. Podemos saber exatamente o tipo que será passado para um método na sua chamada. Podemos ter a certeza de que determinada variável terá os métodos que esperamos e assim não corremos o risco de pedir que um objeto faça algo que ele não é capaz de fazer. Essas são as vantagens da tipagem estática e são vantagens que não estão presentes nas linguagens que usam tipagem dinâmica. Isso faz com que a tipagem dinâmica exija mais disciplina ao escrever o código.
Por outro lado as linguagens de tipagem dinâmica oferecem recursos interessantes no quesito de metaprogramação. Pense em como podemos realizar metaprogramação em Java. Temos a classe Class que possui uma lista de métodos, porém esses métodos só podem ser definidos em tempo de compilação. O compilador verifica se o contrato definido está sendo cumprido. Aliás, essa questão de contrato é algo importante que devemos ter em mente quando programamos com tipagem estática. Veja um exemplo em Java:
interface Helper{
public void helping();
public void helpingALot();
}
Essa interface expressa um contrato a ser cumprido por qualquer objeto que aderir a ela. A partir do momento em que uma classe implementar essa interface, é obrigada a possuir uma implementação desse método como pode ser observado no código a seguir:
public class Man implements Helper {
public void helping(){
System.out.println(“I’m a man helping.”);
}
public void helpingALot(){
System.out.println(“I’m a man helping a lot!!!”);
}
}
Vamos ver agora o contrato sendo posto em prática, através da tipagem estática:
public static void helpMe(Helper helper){
helper.helping();
}
public static void main(String args[]){
helpMe(new Man());
}
O resultado desse código é I’m a man helping.
Repare que deixamos explícito que somente objetos aderentes ao contrato estabelecido por Helper podem ser passados para o método helpMe(). Isso acontece por causa da tipagem estática. Isso é Design by Contract. Orientamos o design do nosso código para que exija um contrato específico e também possua aderência à um contrato também. Apesar de parecer mais seguro isso é bem restritivo e em algumas situações isso pode ser um problema.
Considere o exemplo acima. Estamos restringindo o recebimento de ajuda apenas para objetos do tipo Man (porque somente Man implementa Helper). Porém estamos automaticamente excluindo a opção de receber ajuda de outros objetos que possuam o método helping() sem nem mesmo implementar a interface Helper. Na verdade o que precisamos é de um objeto que possua o método helping e não de um objeto que implemente Helper. Continuando o exemplo, pense que uma Woman pode ser capaz de ajudar tanto quanto um Man, então considere o seguinte código:
public class Woman {
public void helping(){
System.out.println(“I’m a Woman helping.”);
}
}
Nesse caso, uma Woman poderia servir para o que precisamos sem problema algum. Veja o código a seguir e pense sobre o resultado:
public static void helpMe(Helper helper){
helper.helping();
}
public static void main(String args[]){
helpMe(new Man());
helpMe(new Woman());
}
Bom, nesse caso receberíamos uma InvalidArgumentException porque não podemos passar para o método helpMe() um objeto que não adere ao contrato mesmo sendo capaz de executar a aplicação.
No entanto, mude as extensões de seus arquivos de .java para .groovy e utilize as ferramentas de groovy para compilar e executar o código acima. O resultado será:
I’m a man helping.
I’m a Woman helping.
Essa grande diferença fica ainda maior se considerarmos que nas linguagens dinâmicas, como Groovy, podemos adicionar métodos ao objetos em tempo de execução, o que nos termos apresentados significa poder adicionar capacidade de execução dinamicamente e conforme necessário. Isso determina que o design foca em capacidade de execução e não em um contrato pré-estabelecido. Isso tem nome e pode ser considerada um quebra de paradigma em arquitetura de aplicações. Chame de Design by Capability.
Muito bom o artigo!
Uma linguagem fortemente tipada, como o java, tem suas vantagens e desvantagens. Por outro lado, o poder de linguagens fracamente tipadas, como o ruby, é a flexibilidade e expressividade do código. Por exemplo, em ruby podemos implementar callbacks que podem ser utilizados por qualquer objeto. No java poderíamos chamar isso de inner classes, e no C poderiamos chamar de ponteiros de função. Porém no caso do ruby o código fica muito mais bonito por causa da expressividade da linguagem. E é bom lembrar que expressividade anda junto com produtividade!
Você está certíssimo Ricardo….
Só tem um detalhe. Tipagem Dinâmica é diferente de Tipagem Fraca. Groovy e Ruby são exemplos de linguagens de tipagem forte porém dinâmicas. Java e C# são exemplos de linguagens de tipagem forte e estática. Perl é um exemplo de linguagem de tipagem dinâmica e fraca. Por isso, muito cuidado na expressão “linguagens fracamente tipadas”.
Só uma contribuição para seu comentário.