CINCO PERGUNTAS SOBRE O DESIGN DE LINGUAGENS DE PROGRAMAÇÃO
OriginalMaio de 2001
(Estas são algumas notas que fiz para uma discussão em painel sobre o design de linguagens de programação no MIT em 10 de maio de 2001.)
1. Linguagens de Programação São para Pessoas.
As linguagens de programação são a forma como as pessoas se comunicam com os computadores. O computador ficaria igualmente 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 a 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.
Os 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 é o design de pontes. Aí, seu trabalho é principalmente uma questão de atravessar uma determinada distância com o menor material possível. O outro extremo é o design de cadeiras. Os designers de cadeiras têm que passar seu tempo pensando sobre os traseiros humanos.
O software varia da mesma maneira. Projetar algoritmos para rotear dados através de uma rede é um problema agradável e abstrato, como projetar pontes. Enquanto projetar linguagens de programação é como projetar cadeiras: tudo sobre lidar com as fraquezas humanas.
A maioria de nós odeia admitir isso. Projetar sistemas de grande elegância matemática soa muito mais atraente para a maioria de nós do que se render às 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 adequar à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 ninguém gostaria de programar em uma linguagem onde todas as variáveis fossem a letra x com índices inteiros.
2. Projete para Você e Seus Amigos.
Se você olhar para a história das linguagens de programação, muitas das melhores eram linguagens projetadas para seus próprios autores usarem, e muitas das piores foram projetadas para outras pessoas usarem.
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ê. 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 é bastante de baixo nível, mas foi projetada para seus autores usarem, e é por isso que os hackers gostam dela.
O argumento a favor de projetar linguagens para programadores ruins é que há mais programadores ruins do que bons programadores. Isso pode ser verdade. 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? 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 as projetadas para outras pessoas) têm a atitude de uma governanta: elas tentam impedir você de fazer 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 possível.
Quando aprendi Lisp pela primeira vez, o que mais gostei foi que ela me considerava um parceiro igual. Nas outras linguagens que havia aprendido até então, havia a linguagem e havia meu programa, escrito na linguagem, e os dois eram muito separados. Mas em Lisp, as funções e macros que eu escrevia eram iguais àquelas que compunham a própria linguagem. Eu poderia reescrever a linguagem se quisesse. Tinha o mesmo apelo que o software de código aberto.
4. Mire na Brevidade.
A brevidade é subestimada e até mesmo desprezada. Mas se você olhar para o coração dos hackers, verá que eles realmente amam isso. Quantas vezes você ouviu hackers falarem com carinho de como, digamos, em APL, eles poderiam fazer coisas incríveis com apenas algumas linhas de código? Acho que qualquer coisa que pessoas realmente inteligentes realmente amam vale a pena prestar atenção.
Eu acho que quase qualquer coisa que você possa 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 até a 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 por esclarecimentos e reservas e avisos e casos especiais. Se você se forçar a encurtar o manual, no melhor dos casos, você o faz consertando as coisas na linguagem que exigiam tanta explicação.
5. Admita o que é Hacking.
Muitas pessoas desejam que o hacking seja matemática, ou pelo menos algo como uma ciência natural. Eu acho que o hacking é mais como a arquitetura. A arquitetura está relacionada à física, no sentido de que os arquitetos têm que projetar edifícios que não desmoronem, mas o objetivo real dos arquitetos é fazer grandes edifícios, não fazer descobertas sobre a estática.
O que os hackers gostam de fazer é criar ótimos programas. E eu acho que, pelo menos em nossa própria mente, 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, é tão valioso projetar uma linguagem que os programadores amarão quanto projetar uma horrível que incorpore alguma ideia sobre a qual você possa publicar um artigo.
1. Como Organizar Grandes Bibliotecas?
As 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 demorar mais para encontrar a função da 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 deixar seu manual mais grosso. (Os manuais da Symbolics foram um caso em questão.) 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 de Prefixo?
Este é um problema em aberto no sentido de que me perguntei sobre isso 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 muito da impopularidade do Lisp seja simplesmente por ter uma sintaxe desconhecida. Se fazer algo a respeito, se for verdade, é outra questão.
3. O Que Você Precisa para Software Baseado em Servidor?
Acho que muitos dos aplicativos mais emocionantes que serão escritos nos próximos vinte anos serão aplicativos baseados na Web, ou seja, programas que ficam no servidor e conversam com você por meio de um navegador da Web. E para escrever esse tipo de programa, talvez precisemos de algumas coisas novas.
Uma coisa que precisaremos é suporte para a nova maneira como os aplicativos baseados em servidor são lançados. Em vez de ter um ou dois grandes lançamentos por ano, como o software de desktop, os aplicativos baseados em servidor são lançados como uma série de pequenas alterações. 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, o software baseado em servidor também precisa ser projetado para ser modificável. Você precisa poder alterá-lo facilmente, ou pelo menos saber o que é uma pequena alteração e o que é uma alteração importante.
Outra coisa que pode se revelar útil para o software baseado em servidor, surpreendentemente, são as continuações. No software baseado na Web, você pode usar algo como o estilo de passagem de continuação 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 Restam a Serem 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 até mesmo parâmetros-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 Linguagem Que Quiser.
Programas de aplicativos de escrita usados para significar escrever software de desktop. E no software de desktop há um grande viés em direção a escrever o aplicativo na mesma linguagem do sistema operacional. E então, dez anos atrás, escrever software praticamente significava escrever software em C. Eventualmente, uma tradição evoluiu: os programas de aplicativos não devem ser escritos em linguagens incomuns. E essa tradição teve tanto tempo para se desenvolver que as pessoas não técnicas, como gerentes e capitalistas de risco, também a aprenderam.
O software baseado em servidor acaba com todo esse modelo. Com o software baseado em servidor você pode usar qualquer linguagem que quiser. Quase ninguém entende isso ainda (especialmente não gerentes e capitalistas de risco). Alguns hackers entendem isso, e é por isso que até ouvimos sobre novas linguagens independentes como Perl e Python. Não estamos ouvindo sobre Perl e Python porque as pessoas as estão usando para escrever aplicativos do Windows.
O que isso significa para nós, como pessoas interessadas em projetar linguagens de programação, é que agora potencialmente há uma audiência real para nosso trabalho.
2. A velocidade vem de profilers.
Designers de linguagem, ou pelo menos implementadores de linguagem, gostam de escrever compiladores que geram código rápido. Mas não acho que isso é o 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 pode adivinhar onde esses gargalos estão. Os 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 a velocidade vem na prática. Então talvez fosse um ganho líquido se os implementadores de linguagem dedicassem metade do tempo que teriam gasto fazendo otimizações de compilador e o gastassem escrevendo um bom profiler em vez disso.
3. Você precisa de um aplicativo para impulsionar o design de uma linguagem.
Isso pode não ser uma regra absoluta, mas parece que as melhores linguagens evoluíram junto com algum aplicativo 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 estava escrevendo programas de diferenciação mesmo no primeiro artigo sobre Lisp, em 1960.
É especialmente bom se seu aplicativo resolver algum novo problema. Isso tenderá a impulsionar sua linguagem a ter novos recursos que os programadores precisam. Pessoalmente, estou interessado em escrever uma linguagem que será boa para escrever aplicativos baseados em servidor.
[Durante o painel, Guy Steele também fez esse ponto, com a sugestão adicional de que o aplicativo não deve consistir em escrever o compilador para sua linguagem, a menos que sua linguagem aconteça de ser 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 me surpreenderia se a maioria dos programas tivessem começado como programas descartáveis. E então, se você quiser criar 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 do software.
5. A sintaxe está conectada à semântica.
É tradicional pensar em sintaxe e semântica como sendo completamente separadas. Isso vai soar chocante, mas pode ser que elas não sejam. Acho que o que você quer em sua linguagem pode estar relacionado a como você a expressa.
Eu estava conversando recentemente com Robert Morris, e ele observou que a sobrecarga de operadores é um ganho maior em linguagens com sintaxe infixada. Em uma linguagem com sintaxe prefixada, qualquer função que você define é efetivamente um operador. Se você quiser definir um mais 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 infixada, 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.
Nos anos 1970 estava na moda projetar novas linguagens de programação. Recentemente não tem sido. Mas acho que o software baseado em servidor vai 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. Compartilhamento de tempo.
Richard Kelsey deu isso como uma ideia cujo tempo chegou novamente no último painel, e eu concordo completamente com ele. Meu palpite (e o palpite da Microsoft, parece) é que muito do computação se moverá da área de trabalho para servidores remotos. Em outras palavras, o compartilhamento de tempo está de volta. E acho que vai precisar de 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. Cada vez mais, estávamos começando a ouvir sobre código de bytes, o que me implica 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 é executado, 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 vai 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 enfrentando uma espécie de batalha dos códigos de bytes no momento. Mas eles estão fazendo isso porque o código de bytes é um lugar conveniente para se inserir no processo, não porque o código de bytes é uma boa ideia em si. Pode acontecer que este todo o campo de batalha seja contornado. Isso seria meio divertido.
1. Clientes.
Isso é apenas um palpite, mas meu palpite é que o modelo vencedor para a maioria das aplicações será puramente baseado em servidor. Projetar software que funciona com a suposição de que todos terão seu cliente é como projetar uma sociedade com a suposição de que todos serão honestos. Certamente seria conveniente, mas você tem que assumir que isso nunca vai acontecer.
Acho que haverá uma proliferação de dispositivos que tenham algum tipo de acesso à Web, e tudo o que você poderá assumir sobre eles é que eles podem suportar html simples e formulários. 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 em seu gameboy? Seu relógio? Eu não sei. E não preciso saber se eu apostar em tudo apenas estar no servidor. É simplesmente muito mais robusto ter todo o cérebro no servidor.
2. Programação Orientada a Objetos.
Eu sei que este é um assunto controverso, mas não acho que a programação orientada a objetos seja grande coisa. Acho que é um modelo bom 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 a programação.
Acho que parte da razão pela qual as pessoas em grandes empresas gostam da programação orientada a objetos é porque ela gera muito do que parece trabalho. Algo que naturalmente poderia ser representado como, digamos, uma lista de inteiros, agora pode ser representado como uma classe com todo o tipo de andaimes e agitação.
Outra atração da programação orientada a objetos é que os métodos lhe dão alguns dos efeitos 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 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 da linguagem, acho, é que você não deve construir a programação orientada a objetos muito profundamente. Talvez a resposta seja oferecer coisas mais gerais e subjacentes, e deixar as pessoas projetar quaisquer sistemas de objetos que quiserem como bibliotecas.
3. Design por Comitê.
Ter sua linguagem projetada por um comitê é uma grande armadilha, e não apenas pelos motivos que todos conhecem. Todo mundo sabe que os comitês tendem a produzir designs irregulares e inconsistentes. Mas acho que um perigo maior é que eles não assumirão riscos. Quando uma pessoa está no comando, ele pode assumir riscos que um comitê nunca concordaria.
É necessário correr riscos para projetar uma boa linguagem, no entanto? Muitas pessoas podem suspeitar que o design de linguagem é algo em que você deve se ater bastante perto da sabedoria convencional. Eu 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?