Realidades Paralelas

Sunday, February 19, 2006

Algumas notas soltas

Apenas para registrar coisas que estive pensando hoje.

A questão é: o que é um pesquisador em linguagens de programação, o que ele deve resolver? A primeira pergunta não vai ter resposta aqui, mas a segunda remete ao conselho de Richard Hamming de sempre se perguntar qual é o problema mais importante na sua área; eu já pensei sobre isso algumas vezes, e quase sempre fico de postar os pensamentos aqui e não faço. Agora vai.

O papel da pesquisa em linguagens de programação é desenvolver novas formas de expressar a parte de software dos sistemas computacionais. Com a tendência do hardware se tornar mais genérico, o peso nos sistemas computacionais recai quase todo sobre o software; portanto, ganhos de produtividade nas linguagens de programação se refletem como melhorias na construção e manutenção de todos os sistemas computacionais futuros (e mesmo, graças a técnicas de análise, a sistemas legados). Ou pelo menos deveria ser assim. As coisas avançam na indústria no campo das linguagens, mas a inércia é considerável. De toda forma, acho que isso está mudando; a discussão não cabe aqui. O fato é que eu considero a pesquisa em linguagens como uma parte fundamental e praticamente central da computação; é o pólo ao redor do qual todas as sub-áreas relacionadas a software se acomodam. Mesmo que não seja assim que a indústria vê a coisa.

Quais são os problemas mais importantes em linguagens hoje? Pode-se dizer que concorrência, mobilidade e verificação (incluindo verificações de segurança, mas não restrito a isso) estão entre os principas. É interessante se concentrar nesses problemas hoje em dia.

Ao meu ver, um ponto importante com relação aos três problemas e com a própria natureza da programação de computadores é a questão dos efeitos colaterais. Efeitos colaterais devem ser evitados ao máximo e, quando isso não é possível, controlados. Linguagens imperativas cheias de estado se mostram cada vez mais problemáticas; toda análise que se faz de programas é complicada pela presença de efeitos colaterais arbitrários, e isso atrapalha tanto a concorrência quanto a mobilidade de código e a verificação (especialmente de segurança). Muita gente na indústria e pesquisa estão constatando a mesma coisa. Isso é uma prova que, assim como eu, muita gente acredita nos princípios da programação funcional; aliás, não só funcional, como de qualquer paradigma declarativo. A programação por restrições (constraint programming) é muito promissora para algumas aplicações.

O problema é similar à controvérsia do goto nas décadas de 70 e 80: o programador que pode usar gotos é mais "livre" mas seu código se torna mais difícil de ser entendido e, por contrapartido, analisado automaticamente. Algumas coisas eram mais fáceis, principalmente na década de 70, usando um goto ao invés das construções estruturadas. Com o desenvolvimento das linguagens em uma direção cada vez mais longe dos gotos, isso se tornou completamente irrelevante. É muito difícil, hoje, justificar a necessidade de usar um goto; surgiram algumas alternativas estruturadas e semi-estruturadas a ele, e a própria forma de pensar sobre software atualmente (que é, por bem ou por mal, a orientação a objetos) passa longe de saltos arbitrários.

Com efeitos colaterais é parecido. Reclamava-se que era muito mais complicado programar sem eles, e realmente era, se for considerado, por exemplo, o uso de continuações para modelar efeitos colaterais. Com o desenvolvimento de novas idéias, a situação foi melhorando: as mônadas em Haskell conseguem simplificar pelo menos os casos mais básicos, e em muitas situações escondem boa parte da complexidade envolvida. O problema é que ainda não dá para programar bem em Haskell sem entender as mônadas. E, sendo realista, mônadas são mais complicadas do que qualquer coisa que um programador médio queira entender.

Duas direções parecem possíveis: com o avanço das linguagens de programação e os sistemas relacionados, o aumento de produtividade pode ser suficiente para reduzir o número de programadores necessários. Isso causaria uma divisão parecida com a que ocorre na eletrônica: um pequeno grupo teria o conhecimento altamente especializado para programar componentes gerais, enquanto que a maioria apenas usaria esses componentes. Isso em parte já está acontecendo (vide linguagens de script e bibliotecas gigantescas) mas ainda não na escala desejada. A tendência histórica não parece apoiar a idéia que sobrarão poucos programadores: os ganhos de produtividade obtidos nas últimas décadas serviram para aumentar a demanda de software, e a complexidade do que é requerido, de forma que a demanda por programadores também acabou aumentando, ao invés de diminuir. Imagino que isso não mude tão cedo, com a necessidade cada vez maior de automatizar e informatizar. Parece que eventualmente o mundo inteiro será controlado, medido e modelado por software; como ainda estamos longe disso, a demanda só deve aumentar. Uma possibilidade é uma divisão de trabalho menos rígida, que acredito que é parecido com o que está acontecendo: a maioria programaria em linguagens de domínio específico, enquanto que os especialistas criariam as linguagens e o ferramental necessário. Idéia parecida com a Language Oriented Programming proposta por alguns, mas admitindo que nem todo mundo tem condições de criar linguagens efetivas, por mais que as ferramentas ajudem.

A outra possibilidade não é tão diferente: as idéias como mônadas e sistemas de tipos e efeitos podem ser refinadas e desenvolvidas a ponto que um programador possa usar efeitos colaterais (provavelmente não de forma tão livre como nas linguagens atuais) sem se dar conta nos detalhes que estão por baixo. Claro que alguns precisarão conhecer os detalhes para desenvolver os compiladores e projetar as linguagens, mas isso já acontece hoje. Em relação aos que trabalham programando, só uma minoria conhece em detalhes as técnicas envolvidas no projeto de linguagens e criação de compiladores.

É possível também que, assim como o advento da programação orientada a objetos tornou praticamente irrelevante a discussão de nível mais baixo sobre gotos, o uso cada vez maior de paradigmas declarativos (como a programação lógica e a programação por restrições) torne um tanto quanto irrelevante pensar em usar efeitos colaterais diretamente, exceto para uma pequena parcela de system programmers (sempre achei meio estranho traduzir isso). Isso depende do avanço das implementações para tentar garantir maior eficiência, mas também do avanço do poder computacional do hardware, que é o que tem, historicamente, tornado atrativas construções menos eficientes mas de nível mais alto. Se os processadores multi-núcleo realmente se tornarem dominantes, a simplicidade de modelos declarativos como a concorrência por passagem de mensagens e a programação por restrições pode desalojar de vez o estilo imperativo altamente dependente de efeitos colaterais.

Ora, os programadores costumam reclamar que é "difícil" pensar de maneira funcional (ou outro paradigma declarativo). Mas isso acontece somente porque eles foram treinados para usar efeitos colaterais. Da mesma forma, programadores que aprenderam a programar com muitos gotos tiveram problemas para passar à programação estruturada, e vários dos que aprenderam a estruturada sentiram o choque para mudar para a POO. O que interessa aos pesquisadores é o futuro, e para a indústria o importante é a produtividade; o paradigma no qual a maioria dos programadores é treinada hoje em dia tem algum peso na inércia total, mas isso pode ser mudado (vide as mudanças já ocorridas nessas poucas décadas de computação).

A questão que resta aí é quanto ao modelo de nível mais baixo. Lá no processador o modelo ainda é o da máquina de von Neumann: estado compartilhado e efeitos colaterais são essenciais. Não sei se isso pode mudar, mesmo que os paradigmas dominantes se tornem declarativos. Mas se isso acontecer a arquitetura dos processadores com certeza será influenciada.

Uma idéia interessante nesse sentido é tentar achar meios eficientes de definir construções fundamentais como mônadas. E isso tem uma intersecção com outros assuntos como Typed Assembly Language e Proof-Carrying Code. Tudo indica que as plataformas de software do futuro sejam cada mais virtuais, continuando o que já acontece hoje com a JVM e o .NET CLR. Podemos chegar a um ponto que praticamente todo código de aplicação rodando em uma máquina será código gerenciado por algum grande runtime. Isso abre possibilidades para usar linguagens intermediárias tipadas e proof-carrying code, além de ter plataformas virtuais que não sigam o mesmo modelo computacional do hardware. O CLR se torna cada vez mais "amigável" às linguagens funcionais, e a estratégia da Microsoft promete incluir os princípios funcionais cada vez mais no mainstream. Talvez não seja a melhor estratégia ter apenas poucas plataformas que tentam abarcar tudo, mas isso foi o que aconteceu com o hardware, principalmente hoje em dia, quando cada vez mais o mundo roda sobre a plataforma x86 (mesmo que nem sempre da Intel).

Resumindo: formalizar a concorrência e achar novas formas de expressa-la nas linguagens de programação é interessante e importante, assim como estudar efeitos colaterais, como controla-los e especifica-los. Técnicas formais que chegam aos níveis mais baixos, como Typed Assembly Language e Proof-Carrying Code, também são. São essas as coisas que me ocorrem quando eu penso na pesquisa. Concorrência agora pode se tornar central à minha dissertação, embora que obviamente em uma fatia bem mais modesta: algoritmos para coleta de lixo paralela. Mas estudar o particular é uma forma de observar o geral.

0 Comments:

Post a Comment

<< Home