Archive for the 'linguagens' Category

A maldição da popularidade

Eu definitivamente não estou entre os mais antigos praticantes da indústria do desenvolvimento de software, mas já vi alguns fenômenos se repetirem o suficiente para desconfiar que devem ser alguma espécie de lei universal ou coisa parecida. Como sou um fanático por linguagens de programação, minha observação está nesse campo. Mais precisamente nas comunidades que se formam ao redor delas. Eu sei que comunidade é meio que uma palavra da moda hoje em dia, então pode abandonar este texto e passar para o próximo da sua lista de leitura de feeds de hoje: isso aqui certamente vai ser bem vazio e superficial.

Assim como qualquer coisa, linguagens de programação também passam por um período de maturação antes de se tornarem populares. No início elas só são usadas por verdadeiros geeks de linguagens que se divertem em procurar não a próxima grande revolução, mas boas idéias em termos de expressividade. Muitos deles nem chegam a usar direito as linguagens, preferindo aprofundar-se em uma e só ficar de olho em outra meia dúzia.

A maioria dessas pessoas atraídas nessa fase embrionária são programadores excepcionais e começam a ajudar a fazer várias das bibliotecas que vão servir de apoio para as massas que virão a usar a linguagem dali a alguns anos. Eles não fazem isso porque querem ser os senhores daquelas pequenas comunidades no futuro, mas simplesmente porque gostam e se divertem com isso. Afinal de contas, o que pode ser mais divertido do que fazer seu próprio cliente HTTP, por exemplo?

Não precisa responder.

Quando estão nesta fase, as listas de discussão, blogs e fórums sobre essas linguagens costumam ser bastante interessantes. O cara que está fazendo o cliente HTTP conversa com o cara que está tentando melhorar a biblioteca de coleções e todos têm idéias boas para dar. Toda semana alguém bola uma nova expressão idiomática elegante e você se impressiona cada vez mais. Começa a surgir o sotaque da linguagem.

Contraste isso com o que costuma acontecer cinco a dez anos depois se a linguagem chegar a se tornar popular. Neste ponto as listas de discussão começam a se repetir e parece que todo mundo só quer saber como redimensionar uma imagem para mostrar numa aplicação web.

Hora de partir para a próxima linguagem…

Não sei exatamente porque, mas as comunidades pequenas funcionam melhor. Talvez porque os geeks iniciais sejam simplesmente mais interessantes do que a horda de invasores que só querem “fazer um sisteminha” e usar a nova linguagem da moda. A linguagem não costuma mudar muito neste meio tempo. O sotaque usado pelos mais antigos continua mais ou menos o mesmo, mas a comunidade cresce. Com o aumento do número de participantes, qualquer um esperaria que aumentasse a quantidade de boas idéias. Mas ao invés disso, elas parecem diminuir. Ao invés de serem um grupo organizado de pessoas, as multidões se comportam mais como uma manada de touros: ficam pastando no mesmo lugar até que alguém resolva correr tresloucadamente para um lado, hora em que todo mundo decide fazer o mesmo e que alguns são atropelados no meio do processo.

Quando comecei a me interessar por Ruby, era bastante instrutivo acompanhar a ruby-talk. Dava pra distinguir facilmente a voz de gente como Jim Weirich e Hal Funton. Agora, três anos e várias reportagens em grandes revistas depois, tudo o que se vê nos mais variados fóruns da linguagem são as mesmas perguntas sobre como estabelecer relacionamentos NxN. Pelo menos a comunidade Ruby ainda não chegou na proporção da Java, onde encontra-se facilmente gente tentando desenhar diagramas de seqüência para qualquer porção de código que precise ser escrita.

Há coisas que fazem bem para uma linguagem de programação e ser citada em revistas de grande circulação não é uma delas. Isso com certeza faz com que mais gente tome conhecimento, mas as pessoas que importam já haviam sido apresentadas à tecnologia por outros meios. Estas são as pessoas que lêem, pesquisam e estão sempre tentando permanecer atualizados em relação a sua arte. Muito antes dos grandes canais descobrirem as novas tecnologias, elas já sabiam delas através de canais mais alternativos (e mais rápidos e vibrantes) como blogs, listas de discussão e fóruns. São essas pessoas que têm as idéias brilhantes, que escrevem as primeiras bibliotecas, que determinam o rumo das comunidades nascentes, enfim, que realmente fazem a diferença.

Claro que os grandes canais ajudam a dar visibilidade às tecnologias e tornam as coisas mais fáceis para os infelizes que precisam convencer doze níveis de gerência antes de usar qualquer novidade, mas a tecnologia em si não necessariamente evolui mais rápido por causa disso. As pessoas que fazem alguma diferença seriam atraídas pelos méritos da tecnologia de qualquer modo, sem precisar do catalisador da popularidade. A popularidade tem suas vantagens, mas é uma maldição disfarçada. Gente demais na maioria das vezes atrapalha ao invés de ajudar, obrigando os geeks do início a fazer malabarismos para encontrar o que ainda há de relevante e afastando os novos geeks que teriam boas idéias com todo o barulho.

Mais sobre aquele programador Java que você não quer

Houve muitos comentários interessantes aqui sobre meu último texto e alguns deles falavam em algo chamado “lógica de programação”. Um dos leitores comentou que muita gente se limita a aprender uma nova sintaxe, mas continua usando a mesma lógica para programar (*). Ou seja, continua a pensar do mesmo jeito.

Não há sentido em aprender uma nova linguagem assim.

Não existe “a” lógica de programação, apenas “uma” lógica de programação. Quando escrevi o texto anterior era nisso que eu estava pensando, mas precisei de outras pessoas para me abrir os olhos. O importante é que cada linguagem tem uma forma diferente de interpretar a máquina, uma nova filosofia. O que você vai querer aprender é isso, não a sintaxe simplesmente.

Não há grandes ganhos em aprender C# se você já sabe Java, porque o modelo de pensamento das duas é basicamente o mesmo (e conseguir um exemplo foi bem difícil, já que até mesmo neste caso ainda há o que se aproveitar). Mas a lógica para programar é bem diferente se você usar Haskell no lugar de C. Para quem está acostumado com linguagens em que efeitos colaterais são a regra e não a exceção, aprender Haskell dói. É a dor do cérebro ajustando-se a uma linha de pensamento diferente.

Nem precisamos ir tão longe assim para observarmos a dor. Acontece até mesmo quando se passa de C para C++ (por causa das noções de orientação a objetos) e de Python para Io (por causa da orientação a objetos sem classes). A causa disso tudo é a necessidade de absorver uma lógica diferente. Pensar que existe uma única lógica de programação só vai piorar as coisas. Novas linguagens demoram tanto para se disseminar também porque as pessoas acham que já dominam “lógica de programação” há muito tempo e que só precisam se adaptar a uma sintaxe nova. Elas não querem aceitar a dor.

A moral dessa história já foi escrita por Alan Perlis e citada pelo grande Peter Norvig há muito tempo: “Uma linguagem que não afeta seu modo de pensar sobre programação, não é digna de ser estudada.” A conclusão direta disso é que o que devemos procurar em uma linguagem é um novo modo de pensar, não uma sintaxe nova para o antigo.

* Estas não foram as palavras exatas dele, mas acho que é uma interpretação válida

Você não vai querer um programador Java

Muito menos um programador C#, Delphi ou Visual Basic. Para falar a verdade, o que você quer não é nem mesmo um programador Python, Ruby ou Lua.

Este texto também não é um elogio aos programadores Haskell. Você também não vai querer um desses.

Se você tem um problema para ser resolvido com algum programa de computador, o que você precisa é de um programador. Simples assim.

Ninguém precisa da especialização em nenhuma linguagem ou plataforma específica para começo de conversa, mas para programar computadores com certeza você vai precisar de um programador. A verdade é que ele vai precisar de muitas outras habilidades além de proficiência com um compilador, mas se você contratar alguém que não sabe programar, terá uma bela enrascada em mãos. Não importa quantos analisadores de problemas e desenhadores de retângulos sua equipe tiver, se eles não puderem conseguir que um computador faça alguma coisa, seu projeto vai ser um fiasco na certa. A não ser — é claro — que os retângulos possam ser transformados de algum modo em instruções detalhadas executáveis por um computador.

Mas nesse caso você teria programadores. Só aconteceria deles programarem com retângulos, mas ainda assim seriam programadores.

Conhecer uma única linguagem de programação não é um empecilho somente porque muito provavelmente ela não vai mais ser a melhor ferramenta para o trabalho daqui a três ou quatro anos, mas porque mostra uma incapacidade (ou falta de vontade) para aprender. O que nenhum cliente deveria querer são programadores altamente especializados a ponto de conhecer uma única linguagem de programação. Ao invés de um programador especialista na plataforma da moda de hoje, o que você precisa é de um que seja capaz de aprender as de amanhã. O que um bom programador mais precisa, como qualquer bom profissional, não é apenas saber usar as ferramentas do presente, mas ter capacidade de aprender as do futuro.

Não se deixe enganar também por programadores de retângulos, mesmo que eles gostem de ser chamados de modeladores, arquitetos ou de qualquer outro nome que esteja na moda na época. Linguagens visuais também são apenas linguagens. São linguagens que, por serem gráficas, podem parecer independentes de linguagem, mas não deixam de ser linguagens. Não importa que o programador desenhe ao invés de escrever, se ele quis se limitar a desenhar, deve ser porque não quer nem se dar ao trabalho de aprender a escrever.

Especialização em excesso além de tudo cria ilhas muito concentradas de conhecimento. Por algum motivo inexplicável, muitos programadores especializados acham que jogam em times adversários, que estão em trincheiras diferentes e que tudo é uma grande guerra. Se quiser experimentar isso, tente publicar uma notícia que simplesmente cite Ruby (nem precisa ser o tema principal) em um fórum Java e observe o que acontece. O triste é que eles acabam isolando a si mesmos dentro de uma comunidade pequena e perdem de aprender o que as pessoas de fora poderiam ensinar.

Gambiarras com nomes

Quando se está projetando uma linguagem de programação nova, é preciso ter um objetivo principal, um tema, em mente. Você pode querer que sua linguagem proporcione diversão, leve uniformidade e simplicidade extremamente a sério ou que sirva de base para o que houver de mais moderno em termos de pesquisa em linguagens de programação. O número de escolhas possíveis é estonteantemente grande, mas uma coisa é certa: não se pode ter tudo ao mesmo tempo. Não dá para incluir todos os recursos que puder imaginar na sua linguagem nova porque ela seria muito difícil de aprender.

Então nos fim das contas, é preciso escolher o que entra e o que fica de fora. Algumas coisas que ficaram de fora podem ser incluídas em bibliotecas e outras publicadas em artigos e livros e chamadas de padrões de projeto. Os padrões precisam existir porque nenhuma linguagem é a melhor alternativa para todos os trabalhos. Por causa disso as pessoas acabam inventando pequenas gambiarras para resolver alguns problemas comuns que a linguagem não resolveu. A cultura da linguagem influencia as pessoas quando estão bolando essas gambiarras e assim os padrões surgem em várias equipes independentemente.

Um padrão não é nada mais que uma gambiarra para contornar fraquezas de algumas linguagens. Estas fraquezas são completamente naturais. Não se espera que toda linguagem consiga dar suporte a todo tipo de construção, mas que seja boa naquilo a que se propõe. Já que não há como ter suporte direto a tudo que se possa pensar, as pessoas começam a criar construções padronizadas para cada tipo de trabalho. Estas construções são os padrões.

Antes da orientação a objeto tornar-se a panacéia que é atualmente e ser requisito primordial para toda e qualquer linguagem de largo uso, ela já era utilizada na forma de padrões em linguagens como C. Uma das formas de se fazer isso era ter uma estrutura de dados para armazenar os valores dos atributos e os endereços para o código executável das funções que operavam sobre os atributos (os famigerados métodos). Deste modo os dados e as operações sobre eles ficam agrupados, exatamente como nos nossos objetos de hoje. Quando alguém queria executar uma operação sobre um objeto bastava usar o endereço de memória indicado nele próprio. Com esta organização ainda é possível ter coisas como herança e classes abstratas. Este padrão é bem interessante se você quiser desvendar como seu código orientado a objeto é executado pela máquina, mas o objetivo deste artigo não é ensinar como fazer objetos em C e quem estiver interessado em mais detalhes pode dar uma olhada no artigo do Mark Dominus.

Se o termo fosse tão popular na época quanto é hoje, essa construção poderia muito bem ter sido classificada como padrão de projeto. Ela não teve esta honra, mas foi tão aceita e utilizada que acabou sendo incorporada em linguagens posteriores, como C++ e Java. Com estas novas linguagens não era preciso lembrar de construir a estrutura de dados ou evitar utilizar os membros tidos como privativos, tudo isto podia ser controlado automaticamente pelos compiladores e interpretadores. Quando uma linguagem incorpora alguma construção, as pessoas começam a pensar de forma mais abstrata e acabam surgindo novos padrões sobre os antigos. De fato, seria difícil imaginar que teríamos padrões como o Visitor ou o Iterator hoje se ainda precisássemos nos preocupar em controlar ponteiros de funções dentro de estruturas de objetos.

No entanto, os padrões são aplicáveis a linguagens específicas. O caso dos Iteradores1 é bem interessante. Eles são uma solução para o problema de executar um determinado trecho de código (uma função) sobre todos os elementos de algum tipo de recipiente. Em linguagens funcionais, como Haskell, este problema não é nem um problema porque um de seus principais propósitos é permitir tratar funções como cidadãos de primeira classe e possibilitar passá-las de um lado para o outro como qualquer outro valor. Iteradores também desaparecem na maior parte das linguagens que suportam blocos anônimos, como Ruby. Se alguém quiser muito, pode até usar um Iterador em Ruby, mas não há nenhum motivo para fazer isso quando pode-se usar blocos anônimos. Estas linguagens eliminam a necessidade deste padrão porque ele pode ser incorporado à linguagem na forma de bibliotecas.

Algumas linguagens possuem mesmo esta capacidade de permitir que os padrões sejam escritos apenas uma vez e reutilizados muitas outras. Deve ser por isso que Paul Graham parece não gostar de padrões. Ele é um programador Lisp e o modo de se fazer um programa Lisp é inventar um dialeto (essencialmente uma linguagem nova) e utilizá-lo (junto com um monte de parênteses) para resolver o problema. Os padrões acabam sendo incorporados ao novo dialeto durante seu desenvolvimento e não faz muito sentido catalogar esses padrões se eles já estão codificados. Inventar uma linguagem nova para cada problema pode parecer exagero e realmente é, se a linguagem base não tiver sido projetada para isso. Mas Lisp foi e não há nada mais natural para um programador Lisp do que fazer um pequeno dialeto.

Enquanto existirem computadores para serem programados, isso vai continuar a acontecer. As melhores gambiarras vão ser chamadas de padrões e os melhores padrões serão incorporados a novas linguagens, tornando-se invisíveis ou desnecessários. Foi assim que aconteceu com chamadas de subrotinas, classes, objetos e outras várias construções que hoje achamos extremamente naturais. O melhor de tudo é que esta evolução toda nos permite pensar cada vez mais longe da máquina e de forma mais natural. Assim podemos manter o ciclo inventando novas gambiarras que podem se tornar novos padrões que por sua vez podem ser incorporados a novas linguagens.

Padrões são gambiarras, mas não são como qualquer gambiarra. O que realmente diferencia um padrão de projeto das demais gambiarras é o fato de ter um nome. Os nomes dos padrões permitem que os programadores se comuniquem mais eficientemente. Eles podem se referir às gambiarras pelo nome, ao invés de dizer “acho que aqui podemos usar uma gambiarra que eu vi em outro sistema” e depois precisar de um bom tempo para explicar.

A maior força dos padrões é também sua maior fraqueza. Um vocabulário rico ajuda muito os experientes, mas pode atrapalhar os novatos. Para começar a programar sério em uma linguagem onde toda solução precisa a ser repleta de convenções e padrões, não basta aprender somente a linguagem base: é preciso aprender também todo um vocabulário de padrões. Mais ou menos como aprender um segundo idioma não é só estudar a gramática para formar frases estruturalmente corretas, mas também manter-se em contato com o idioma a fim de incrementar o vocabulário e aprender como os nativos falam para evitar soar como um tradutor automático.

1. Iterador é o nome que uso em português para Iterator, caso você esteja caindo do septuagésimo-terceiro andar da Torre de Babel e ainda não tenha ligado o nome à pessoa

Elephant typing

Devido à recente explosão de popularidade das linguagens dinâmicas, você provavelmente já deve ter ouvido falar de duck typing. É a noção que o tipo de um objeto é determinado exclusivamente pelas mensagens às quais ele pode responder. Se dois objetos quaisquer respondem a um mesmo conjunto de mensagens, eles podem ser considerados do mesmo tipo. É uma versão programática do já clássico dito “se algo grasna como um pato e nada como um pato, deve ser um pato.”

Para quem está acostumado com definição estática de tipos, talvez faça sentido pensar que é como se houvesse interfaces definidas dinamicamente de acordo com as necessidades do código em execução. Algoritmos de ordenação, por exemplo, conseguem trabalhar com qualquer conjunto de objetos comparáveis. Ou seja, que forneçam métodos de comparação como maior, menor e igual. Com duck typing, estes objetos não precisam indicar que satisfazem a interface Comparable, precisam apenas responder às mensagens esperadas e o algoritmo de comparação pode tratar todos como comparáveis. Afinal eles respondem se são maiores ou menores que os outros, portanto devem ser comparáveis.

O tempo passa, as linguagens evoluem, surgem novos conceitos e os animais vão ficando maiores. Steve de Korte, criador da linguagem Io, em uma entrevista de julho do ano passado (ouça a primeira parte também) introduziu um conceito que dá para chamar de elephant typing. Ele usa elefantes como analogia para explicar programação com protótipos.

O modo mais comum de criar um objeto em uma linguagem baseada em protótipos é clonar um objeto pré-existente e especializar o clone do modo que for necessário. O clone inicialmente possui as mesmas propriedades que o objeto original e pode ser descrito a partir daí evitando repetição. Para descrever o Dumbo por exemplo, você poderia dizer:

“Dumbo é um elefante como aquele que você viu no zoológico. Só que é um filhote e por isso é um pouco menor. As orelhas dele são bem maiores e ele pode voar. Além disso, ele carrega uma pena na tromba a maior parte do tempo por acreditar que é ela que o faz voar.”

Há objetos, mas não há classes. O programador especifica somente as diferenças do clone para o protótipo. Se mais tarde algo for descoberto sobre o protótipo, também vai valer para o clone. Por exemplo, se depois você descobre que o elefante do zoológico tem medo de ratos, pode presumir que Dumbo também tem. Trocando em miúdos, em Io, se você alterar um objeto adicionando um método novo ou modificando o valor de um atributo, a alteração é propagada para todos os descendentes. Entretanto, este não necessariamente é o comportamento dos protótipos das demais linguagens.

Ano novo, linguagem nova

Não que seja algum tipo de tradição pessoal de ano novo, está mais para coincidência. Mas ano passado, mais ou menos no começo do ano, comecei a estudar Ruby. Minha experiência anterior sempre tinha sido com linguagens compiladas e eu estava me interessando bastante pelo lado dinâmico e interpretado da vida. Aconteceu de Ruby estar bastante comentada na época e acabou sendo a escolha mais óbvia. Depois de um ano, a linguagem está bem mais na moda e o projeto que comecei para estudar está começando a tomar corpo.

A mente é uma fera faminta por novidades e, se você alimentá-la periodicamente, ela pode acabar gerando algumas maravilhas próprias. Uma linguagem nova é um ótima opção para essa dieta. Uma linguagem não é só uma ferramenta, é toda uma escola de pensamento nova e vem acompanhada de um mundo de idéias fresquinhas. Estar em contato com outros mundos é uma boa forma de expandir os horizontes e facilitar o surgimento das boas idéias. Ruby tem feito exatamente isto por mim. Conhecer duck typing, geração de código em tempo de execução e as tão faladas DSLs em Ruby com certeza abre algumas possibilidades para a imaginação, se não para o raciocínio. Mesmo que eu não esteja trabalhando com a linguagem para resolver um determinado problema, o que ela me ensinou já faz bem porque está enraizado na cabeça. Com certeza isso não é exclusividade de Ruby. Se você está trabalhando exclusivamente do lado compilado ou interpretado, aconselho conhecer o outro. E se você não sabe de que lado está, procure saber. O aprendizado é garantido.

Um ano não foi suficiente para que eu possa dizer que conheço profundamente Ruby e acho que vou continuar estudando por muito tempo ainda. Mas acho que já chegou o tempo de apresentar a mim mesmo novos paradigmas. Ultimamente tenho pesquisado sobre linguagens de programação baseadas em protótipos. O que posso dizer com meu limitado conhecimento é que programação baseada em protótipos é um tipo de orientação a objetos.

Só que sem classes!

Numa linguagem orientada a objetos baseada em protótipos o comportamento é inserido diretamente nos objetos. Para criar um método novo, você pega um objeto antigo e adiciona o método diretamente a ele. Não é preciso criar um classe previamente para isso. Se você olhar bem, classes são apenas objetos com instruções especiais sobre como criar outros objetos. Em orientação a objetos puramente baseada em classes, elas são o único meio de criar novos objetos. Com protótipos, objetos podem ser criados a partir de qualquer outro objeto pelo processo de clonagem. O objeto original é chamado de protótipo e daí vem o termo “baseada em protótipos”.

Só de conhecer essa idéia de protótipos, minha cabeça já passou por uma pequena remodelagem. Mas uma coisa é estar a par do conceito, outra é aprender uma linguagem construída sobre ele. Novamente posso estar falando besteira, mas um exemplo de linguagem bastante popular construída sobre a mesma idéia é Javascript. Mas não foi ela que eu escolhi. Se você pesquisar sobre linguagens baseadas em prótipos, vai acabar chegando a Self, que seria minha linguagem escolhida para este ano. Ela já está no pedaço desde os anos 80 e parece ser bastante madura. Uma pequena coisa que impediu de ir em frente foi o fato de não haver um compilador/interpretador disponível. Pelo menos não para quem não possui uma máquina Mac OSX ou SPARC com Solaris. Não por enquanto.

Depois de uma pequena saga em busca de uma linguagem baseada em protótipos que eu pudesse realmente usar, acabei chegando a Io, uma linguagem bem simples nascida em Abril de 2002 pelas mãos de um californiano (não sei se o cara realmente nasceu lá, mas é onde ele diz que mora). Já baixei e compilei meu interpretador e tudo parece estar funcionando corretamente por aqui. Até já fiz meu primeiro programa:

"Hello, Io!" println

Io não tem classes, nem operadores aritméticos e nem atribuição. Tudo isso é implementado a partir de passagem de mensagens. Bem simples e uniforme. Além disso, Io não tem palavras-chave.

Mesmo assim funciona.

Isso com certeza é surpreendente.

Nada de errado com tipagem estática

Tipagem estática quer dizer que todos os tipos estão determinados em tempo de compilação e que não mudam durante a execução do programa. Não deve haver problema nenhum com o fato do compilador verificar todos os tipos do seu programa antes de gerar um executável, certo? Isso pode até ser bom. Não há substituto para uma estrutura bem projetada e boa cobertura de testes, mas ter verificação de tipo durante a compilação pode mesmo evitar erros.

Como muita coisa, tipagem estática é uma faca de dois gumes e este é apenas um lado da moeda. O outro lado são as linguagens que exigem que o programador ajude o compilador a descobrir os tipos. Tudo para que eles possam dizer ao programador ‘Não, você não parece ter errado o tipo de nenhuma expressão’. Na presença de uma dessas linguagens, deveriam ser disparados alguns alarmes e deveria haver uma brigada de forças especiais dedicada especificamente a alertar os mais desavisados. Afinal de contas, as máquinas deveriam ajudar a nós e não nós a elas.

A realidade é que, se isso acontecesse, seria um mundo cheio de alarmes porque esse tipo de linguagem está em toda parte. Mas essa onipresença não faz com que ser forçado a escrever Integer no início de uma declaração como Integer x = 3 deixe de ser quase um insulto à inteligência. Se x é igual a três e três é um inteiro, é óbvio que x também é um inteiro. A declaração de tipo é só repetição. Repetição é uma coisa em que computadores são bons e pessoas são extremamente ruins. Pessoas ficam entediadas e querem desafios, computadores não precisam disso.

O nome que os pesquisadores arrumaram para esse tipo de repetição é inferência de tipos e deveria ser feita por toda linguagem e compilador sempre que possível. Mais: elas deveriam ser projetadas para que sempre fosse possível inferir tipos. Poupar a paciência dos programadores é sempre uma boa idéia e compiladores que precisam de tudo mastigado não fazem isso.

O raciocínio pode até ser estendido para expressões mais complexas. Aqui há uma definição de função em uma linguagem fictícia (que muito provavelmente é sintaxe válida em alguma linguagem real):

fac(n) {
    if (n == 0) return 1;
    else return n * (fac( n - 1));
}

Temos uma função fac que recebe um n, que por sua vez é usado em duas expressões dentro da definição da função. Na primeira, ele é comparado com zero e, na segunda, é subtraído de um. Portanto, n é algo que pode ser comparado e subtraído: um número. Isso faz da nossa função uma função sobre números. Mas, para falar um pouco de matematiquês, qual é o contra-domínio da função? Eu sei que devo passar um número para ela, mas o que vou receber em troca?

Essa é fácil, é só ver o que ela retorna. Temos duas expressões que retornam valores, a primeira retorna o valor um (um número). Isso faz de fac uma função de número para número, mas o tipo da segunda expressão de retorno precisa coincidir com o da primeira para que o código esteja consistente. Como n é um número que está sendo multiplicado por outro número (o fatorial do número anterior a ele), os tipos batem.

Estes dois exemplos são bem simples, mas inferir tipos realmente não é muito complicado. Podemos continuar aumentando a complexidade das expressões que ainda será possível inferir tipos. Tudo isto pode ser feito sem que o programador precise prover informação de tipos e em tempo de compilação. Por isso inferência de tipos é diferente de duck typing. Não quer dizer somente que o programador não precisa declarar os tipos, mas que além disso ele não vai precisar esperar até executar o programa para detectar os erros.



Seguir

Obtenha todo post novo entregue na sua caixa de entrada.