CINCO PERGUNTAS SOBRE DESIGN DE LINGUAGEM
OriginalMaio de 2001
(Estas são algumas anotações que fiz para um painel de discussão sobre design de linguagem de programação no MIT em 10 de maio de 2001.)
1. Linguagens de programação são para pessoas.
Linguagens de programação são como as pessoas falam com computadores. O computador ficaria feliz falando qualquer linguagem que fosse inequívoca. A razão pela qual temos linguagens de alto nível é porque as pessoas não conseguem lidar com linguagem de máquina. O objetivo das linguagens de programação é evitar que nossos pobres e frágeis cérebros humanos sejam sobrecarregados por uma massa de detalhes.
Arquitetos sabem que alguns tipos de problemas de design são mais pessoais do que outros. Um dos problemas de design mais limpos e abstratos é projetar pontes. Lá, seu trabalho é, em grande parte, uma questão de abranger uma determinada distância com o mínimo de material. A outra ponta do espectro é projetar cadeiras. Designers de cadeiras têm que gastar seu tempo pensando em bundas humanas.
O software varia da mesma forma. Projetar algoritmos para roteamento de dados por uma rede é um problema abstrato e agradável, como projetar pontes. Enquanto projetar linguagens de programação é como projetar cadeiras: é tudo sobre lidar com fraquezas humanas.
A maioria de nós odeia reconhecer isso. Projetar sistemas de grande elegância matemática parece muito mais atraente para a maioria de nós do que bajular as fraquezas humanas. E há um papel para a elegância matemática: alguns tipos de elegância tornam os programas mais fáceis de entender. Mas a elegância não é um fim em si mesma.
E quando digo que as linguagens têm que ser projetadas para se adequarem às fraquezas humanas, não quero dizer que as linguagens têm que ser projetadas para programadores ruins. Na verdade, acho que você deve projetar para os melhores programadores , mas mesmo os melhores programadores têm limitações. Não acho que alguém gostaria de programar em uma linguagem em que todas as variáveis fossem a letra x com subscritos inteiros.
2. Crie para você e seus amigos.
Se você olhar para a história das linguagens de programação, muitas das melhores foram projetadas para uso de seus próprios autores, e muitas das piores foram projetadas para uso de outras pessoas.
Quando as linguagens são projetadas para outras pessoas, é sempre um grupo específico de outras pessoas: pessoas não tão inteligentes quanto o designer da linguagem. Então você obtém uma linguagem que fala com você de cima para baixo. Cobol é o caso mais extremo, mas muitas linguagens são permeadas por esse espírito.
Não tem nada a ver com o quão abstrata a linguagem é. C é bem low-level, mas foi projetada para seus autores usarem, e é por isso que hackers gostam dela.
O argumento para projetar linguagens para programadores ruins é que há mais programadores ruins do que bons. Pode ser. Mas esses poucos bons programadores escrevem uma porcentagem desproporcionalmente grande do software.
Estou interessado na questão, como você projeta uma linguagem que os melhores hackers vão gostar? Acontece que acho que isso é idêntico à questão, como você projeta uma boa linguagem de programação?, mas mesmo que não seja, é pelo menos uma questão interessante.
3. Dê ao programador o máximo de controle possível.
Muitas linguagens (especialmente aquelas projetadas para outras pessoas) têm a atitude de uma governanta: elas tentam impedir que você faça coisas que elas acham que não são boas para você. Eu gosto da abordagem oposta: dê ao programador o máximo de controle que você puder.
Quando aprendi Lisp pela primeira vez, o que mais gostei foi que me consideravam um parceiro igual. Nas outras linguagens que aprendi até então, havia a linguagem e meu programa, escrito na linguagem, e os dois eram muito separados. Mas em Lisp, as funções e macros que escrevi eram exatamente como aquelas que compunham a linguagem em si. Eu podia reescrever a linguagem se quisesse. Ela tinha o mesmo apelo que o software de código aberto.
4. Busque a brevidade.
Brevidade é subestimada e até mesmo desprezada. Mas se você olhar para os corações dos hackers, verá que eles realmente amam isso. Quantas vezes você já ouviu hackers falando carinhosamente sobre como, digamos, na APL, eles poderiam fazer coisas incríveis com apenas algumas linhas de código? Acho que qualquer coisa que pessoas realmente inteligentes realmente amem vale a pena prestar atenção.
Acho que quase tudo que você pode fazer para tornar os programas mais curtos é bom. Deve haver muitas funções de biblioteca; qualquer coisa que possa ser implícita deve ser; a sintaxe deve ser concisa a ponto de ser uma falha; até mesmo os nomes das coisas devem ser curtos.
E não são apenas os programas que devem ser curtos. O manual também deve ser fino. Uma boa parte dos manuais é ocupada com esclarecimentos, reservas, avisos e casos especiais. Se você se forçar a encurtar o manual, na melhor das hipóteses você o faz corrigindo as coisas na linguagem que exigiam tanta explicação.
5. Admita o que é hacking.
Muitas pessoas gostariam que hacking fosse matemática, ou pelo menos algo como uma ciência natural. Eu acho que hacking é mais como arquitetura. Arquitetura está relacionada à física, no sentido de que arquitetos têm que projetar prédios que não caiam, mas o objetivo real dos arquitetos é fazer grandes prédios, não fazer descobertas sobre estática.
O que os hackers gostam de fazer é criar ótimos programas. E eu acho que, pelo menos em nossas mentes, temos que lembrar que é uma coisa admirável escrever ótimos programas, mesmo quando esse trabalho não se traduz facilmente na moeda intelectual convencional de artigos de pesquisa. Intelectualmente, vale tanto a pena projetar uma linguagem que os programadores vão adorar quanto projetar uma horrível que incorpore alguma ideia sobre a qual você pode publicar um artigo.
1. Como organizar grandes bibliotecas?
Bibliotecas estão se tornando um componente cada vez mais importante das linguagens de programação. Elas também estão ficando maiores, e isso pode ser perigoso. Se levar mais tempo para encontrar a função de biblioteca que fará o que você quer do que levaria para escrevê-la você mesmo, então todo esse código não está fazendo nada além de tornar seu manual grosso. (Os manuais da Symbolics foram um exemplo.) Então, acho que teremos que trabalhar em maneiras de organizar bibliotecas. O ideal seria projetá-las de forma que o programador pudesse adivinhar qual chamada de biblioteca faria a coisa certa.
2. As pessoas realmente têm medo da sintaxe dos prefixos?
Este é um problema aberto no sentido de que eu tenho me perguntado sobre ele por anos e ainda não sei a resposta. A sintaxe de prefixo parece perfeitamente natural para mim, exceto possivelmente para matemática. Mas pode ser que grande parte da impopularidade do Lisp seja simplesmente devido a ter uma sintaxe pouco familiar. Se fazer algo sobre isso, se for verdade, é outra questão.
3. O que você precisa para um software baseado em servidor?
Acho que muitos dos aplicativos novos mais empolgantes que serão escritos nos próximos vinte anos serão aplicativos baseados na Web, ou seja, programas que ficam no servidor e falam com você por meio de um navegador da Web. E para escrever esses tipos de programas, podemos precisar de algumas coisas novas.
Uma coisa que precisaremos é de suporte para a nova maneira como aplicativos baseados em servidor são lançados. Em vez de ter um ou dois grandes lançamentos por ano, como software de desktop, aplicativos baseados em servidor são lançados como uma série de pequenas mudanças. Você pode ter até cinco ou dez lançamentos por dia. E, como regra, todos sempre usarão a versão mais recente.
Você sabe como você pode projetar programas para serem depuráveis? Bem, software baseado em servidor também tem que ser projetado para ser mutável. Você tem que ser capaz de mudá-lo facilmente, ou pelo menos saber o que é uma pequena mudança e o que é uma mudança importante.
Outra coisa que pode se tornar útil para software baseado em servidor, surpreendentemente, são continuações. Em software baseado na Web, você pode usar algo como o estilo continuação-passagem para obter o efeito de subrotinas no mundo inerentemente sem estado de uma sessão da Web. Talvez valesse a pena ter continuações reais, se não fosse muito caro.
4. Que novas abstrações ainda precisam ser descobertas?
Não tenho certeza de quão razoável é essa esperança, mas uma coisa que eu realmente adoraria fazer, pessoalmente, é descobrir uma nova abstração-- algo que faria tanta diferença quanto ter funções de primeira classe ou recursão ou mesmo parâmetros de palavra-chave. Isso pode ser um sonho impossível. Essas coisas não são descobertas com tanta frequência. Mas estou sempre procurando.
1. Você pode usar qualquer idioma que quiser.
Escrever programas de aplicação costumava significar escrever software de desktop. E em software de desktop há uma grande tendência a escrever o aplicativo na mesma linguagem do sistema operacional. E então, dez anos atrás, escrever software significava basicamente escrever software em C. Eventualmente, uma tradição evoluiu: programas de aplicação não devem ser escritos em linguagens incomuns. E essa tradição teve tanto tempo para se desenvolver que pessoas não técnicas, como gerentes e capitalistas de risco, também a aprenderam.
Software baseado em servidor destrói todo esse modelo. Com software baseado em servidor, você pode usar qualquer linguagem que quiser. Quase ninguém entende isso ainda (especialmente gerentes e capitalistas de risco). Alguns hackers entendem, e é por isso que ouvimos falar de novas linguagens independentes como Perl e Python. Não estamos ouvindo falar de Perl e Python porque as pessoas estão usando-as para escrever aplicativos do Windows.
O que isso significa para nós, como pessoas interessadas em projetar linguagens de programação, é que agora há potencialmente um público real para o nosso trabalho.
2. A velocidade vem dos criadores de perfil.
Designers de linguagem, ou pelo menos implementadores de linguagem, gostam de escrever compiladores que geram código rápido. Mas não acho que seja isso que torna as linguagens rápidas para os usuários. Knuth apontou há muito tempo que a velocidade só importa em alguns gargalos críticos. E qualquer um que tenha tentado sabe que você não consegue adivinhar onde estão esses gargalos. Profilers são a resposta.
Os designers de linguagem estão resolvendo o problema errado. Os usuários não precisam de benchmarks para rodar rápido. O que eles precisam é de uma linguagem que possa mostrar a eles quais partes de seus próprios programas precisam ser reescritas. É daí que vem a velocidade na prática. Então talvez seria uma vitória líquida se os implementadores de linguagem levassem metade do tempo que gastariam fazendo otimizações de compiladores e o gastassem escrevendo um bom profiler.
3. Você precisa de um aplicativo para conduzir o design de uma linguagem.
Isso pode não ser uma regra absoluta, mas parece que as melhores linguagens evoluíram todas juntas com alguma aplicação que elas estavam sendo usadas para escrever. C foi escrito por pessoas que precisavam dele para programação de sistemas. Lisp foi desenvolvido em parte para fazer diferenciação simbólica, e McCarthy estava tão ansioso para começar que ele estava escrevendo programas de diferenciação mesmo no primeiro artigo sobre Lisp, em 1960.
É especialmente bom se seu aplicativo resolver algum problema novo. Isso tenderá a levar sua linguagem a ter novos recursos que os programadores precisam. Eu, pessoalmente, estou interessado em escrever uma linguagem que seja boa para escrever aplicativos baseados em servidor.
[Durante o painel, Guy Steele também levantou esse ponto, com a sugestão adicional de que a aplicação não deveria consistir em escrever o compilador para sua linguagem, a menos que sua linguagem seja destinada a escrever compiladores.]
4. Uma linguagem tem que ser boa para escrever programas descartáveis.
Você sabe o que é um programa descartável: algo que você escreve rapidamente para alguma tarefa limitada. Acho que se você olhasse ao redor, descobriria que muitos programas grandes e sérios começaram como programas descartáveis. Eu não ficaria surpreso se a maioria dos programas começasse como programas descartáveis. E então, se você quer fazer uma linguagem que seja boa para escrever software em geral, ela tem que ser boa para escrever programas descartáveis, porque esse é o estágio larval da maioria dos softwares.
5. A sintaxe está conectada à semântica.
É tradicional pensar em sintaxe e semântica como sendo completamente separadas. Isso pode soar chocante, mas pode ser que não sejam. Acho que o que você quer na sua linguagem pode estar relacionado a como você a expressa.
Eu estava conversando recentemente com Robert Morris, e ele apontou que a sobrecarga de operadores é uma vitória maior em linguagens com sintaxe infixa. Em uma linguagem com sintaxe prefixa, qualquer função que você define é efetivamente um operador. Se você quiser definir um plus para um novo tipo de número que você criou, você pode simplesmente definir uma nova função para adicioná-los. Se você fizer isso em uma linguagem com sintaxe infixa, há uma grande diferença na aparência entre o uso de um operador sobrecarregado e uma chamada de função.
1. Novas linguagens de programação.
Na década de 1970, era moda projetar novas linguagens de programação. Ultimamente, não é mais. Mas acho que o software baseado em servidor tornará as novas linguagens na moda novamente. Com o software baseado em servidor, você pode usar qualquer linguagem que quiser, então se alguém projetar uma linguagem que realmente pareça melhor do que outras disponíveis, haverá pessoas que correrão o risco e a usarão.
2. Tempo compartilhado.
Richard Kelsey deu isso como uma ideia cuja hora chegou novamente no último painel, e eu concordo completamente com ele. Meu palpite (e o palpite da Microsoft, ao que parece) é que muita computação vai migrar do desktop para servidores remotos. Em outras palavras, o compartilhamento de tempo está de volta. E eu acho que será necessário suporte para isso no nível da linguagem. Por exemplo, eu sei que Richard e Jonathan Rees fizeram muito trabalho implementando o agendamento de processos dentro do Scheme 48.
3. Eficiência.
Recentemente, estava começando a parecer que os computadores finalmente eram rápidos o suficiente. Mais e mais estávamos começando a ouvir sobre código de bytes, o que implica para mim, pelo menos, que sentimos que temos ciclos de sobra. Mas não acho que teremos, com software baseado em servidor. Alguém vai ter que pagar pelos servidores em que o software roda, e o número de usuários que eles podem suportar por máquina será o divisor de seu custo de capital.
Então, acho que a eficiência importará, pelo menos em gargalos computacionais. Será especialmente importante fazer i/o rápido, porque aplicativos baseados em servidor fazem muito i/o.
Pode acontecer que o código de bytes não seja uma vitória, no final. A Sun e a Microsoft parecem estar se enfrentando em uma espécie de batalha dos códigos de bytes no momento. Mas elas estão fazendo isso porque o código de bytes é um lugar conveniente para se inserirem no processo, não porque o código de bytes seja em si uma boa ideia. Pode acontecer que todo esse campo de batalha seja contornado. Isso seria meio divertido.
1. Clientes.
Isto é apenas um palpite, mas meu palpite é que o modelo vencedor para a maioria dos aplicativos será puramente baseado em servidor. Projetar software que funciona na suposição de que todos terão seu cliente é como projetar uma sociedade na suposição de que todos serão honestos. Certamente seria conveniente, mas você tem que assumir que isso nunca acontecerá.
Acho que haverá uma proliferação de dispositivos que terão algum tipo de acesso à Web, e tudo o que você poderá assumir sobre eles é que eles podem suportar HTML e formulários simples. Você terá um navegador no seu celular? Haverá um telefone no seu Palm Pilot? Seu Blackberry terá uma tela maior? Você poderá navegar na Web no seu Gameboy? No seu relógio? Não sei. E não preciso saber se aposto que tudo estará apenas no servidor. É muito mais robusto ter todos os cérebros no servidor .
2. Programação Orientada a Objetos.
Eu percebo que isso é controverso, mas não acho que programação orientada a objetos seja um grande negócio. Acho que é um bom modelo para certos tipos de aplicativos que precisam desse tipo específico de estrutura de dados, como sistemas de janelas, simulações e programas CAD. Mas não vejo por que deveria ser o modelo para toda programação.
Acho que parte da razão pela qual as pessoas em grandes empresas gostam de programação orientada a objetos é porque ela produz muito do que parece ser trabalho. Algo que poderia ser naturalmente representado como, digamos, uma lista de inteiros, agora pode ser representado como uma classe com todos os tipos de andaimes e agitação.
Outra atração da programação orientada a objetos é que os métodos dão a você um pouco do efeito das funções de primeira classe. Mas isso é notícia velha para os programadores Lisp. Quando você tem funções de primeira classe reais, você pode simplesmente usá-las da maneira que for apropriada para a tarefa em questão, em vez de forçar tudo em um molde de classes e métodos.
O que isso significa para o design de linguagem, eu acho, é que você não deve construir programação orientada a objetos muito profundamente. Talvez a resposta seja oferecer coisas mais gerais e subjacentes, e deixar que as pessoas projetem quaisquer sistemas de objetos que queiram como bibliotecas.
3. Design pelo Comitê.
Ter sua linguagem projetada por um comitê é uma grande armadilha, e não apenas pelos motivos que todos conhecem. Todos sabem que comitês tendem a produzir designs irregulares e inconsistentes. Mas acho que um perigo maior é que eles não correm riscos. Quando uma pessoa está no comando, ela pode correr riscos com os quais um comitê nunca concordaria.
Mas é necessário correr riscos para projetar uma boa linguagem? Muitas pessoas podem suspeitar que o design de linguagem é algo em que você deve se ater bem próximo da sabedoria convencional. Aposto que isso não é verdade. Em tudo o mais que as pessoas fazem, a recompensa é proporcional ao risco. Por que o design de linguagem deveria ser diferente?