A comparação entre linguagens de programação (e incluem-se aí os ambientes sob os quais estas linguagens operam) é um assunto quase que inesgotável.
Quando abordado de forma leviana, acaba em discussões que pouco diferem das mesas-redondas futebolísticas: programadores movidos por um ímpeto de paixão e desejo de preservar seu investimento intelectual defendem com unhas e dentes suas linguagens prediletas, agindo como se todo o resto fosse secundário. O argumento também pouco varia: linguagens mais pragmáticas (de menor nível que a escolhida) são sempre “improdutivas” e as mais abstratas (de maior nível) “performam pouco”. Não é exagero afirmar que a maioria esmagadora das discussões sobre o assunto se dá sob este cenário, e é fácil perceber que, assim como suas contrapartes desportivas, pouco avançam.
Uma discussão mais aprofundada requer um estudo igualmente profundo (nas palavras de [Robert Herrick][1], “no pain, no gain”). É preciso compreender não apenas as linguagens que estão sendo comparadas, mas também suas antecessoras. A abordagem histórica é importante porque uma linguagem não surge ao acaso – uma forte motivação é necessária, tal como a existência de um domínio cujos problemas não são apropriadamente descritos (ou processados) nas lingaugens pré-existentes – ao menos na opinião dos criadores da nova linguagem.
Mesmo trilhando este caminho, um erro comum (que já cometi) é concentrar os estudos naquilo que já se conhece. É uma abordagem muito produtiva: se eu trabalho com Java, não vou perder muito tempo com programação funcional; se uso PHP, é mais jogo procurar técnicas que otimizem o meu trabalho do que me envolver com as dificuldades do mapeamento objeto-relacional, e por aí vai.
Esta produtividade tem um custo – fica cada vez mais difícil situar o seu ambiente (e perceber onde ele pode melhorar). E quando a inenvitável mudança tecnológica vier (e sim, ela virá – independente do “padrão de mercado” ou do “imenso legado” – características já atribuídas a tantas outras linguagens, hoje marginais ou extintas), este custo se fará sentir, pois será muito mais difícil migrar para novos paradigmas.
Independente da justificação prática, achei que seria interessante aproveitar as férias da faculdade para preencher algumas lacunas pessoais neste assunto, o que me levou a alguns livros interessantes (que são o verdadeiro tema deste post). Vamos a eles:
A Little Smalltalk</p> Se você, programador Java, já se perguntou por que a classe-mãe-de-todas-as-classes se chama Object (e não “Class”), ou porque chamamos o paradigma de “orientação a objeto” (considerando que o desenho da aplicação acaba lidando mais com as classes do que com os objetos em si), aprender Smalltalk vai acender algumas luzes. E é melhor ainda se este aprendizado se der sob uma ótica isenta de legado. A Little Smalltalk aborda um dialeto específico da linguagem, mas é mais do que suficiente para evidenciar variações sutis (por exemplo, em Smalltalk você não “chama um método”, e sim “envia uma mensagem”). Tais diferenças parecem, numa primeira análise, puramente estéticas/semânticas, mas ajudam a compreender as motivações (e reais limitações) existentes no Java como o usamos hoje. </td> </tr> |
Programming in Common Lisp</p> Lisp é como a Cher: de tempos em tempos volta com plena majestade. Seja quando Paul Graham defende seu aprendizado, seja quando programação funcional se torna o assunto da vez, vira e mexe algo aparece que desperta a curiosidade sobre esta linguagem. Assim como o outro livro, Programming in Common Lisp trata de um dialeto específico, mas suficiente para ajudar a compreender os fundamentos, e separar o hype da realidade. Para quem gosta de construções matemáticas “belas” (i.e., simples em suas definições, mas que possuem ramificações complexas), Lisp é um prato cheio: os reais fundamentos (CAR/CDR, lazy evaluation e cercanias) são bastante sintéticos, mas os desdobramentos (e aplicações) são infindáveis, e, a meu ver, justificam plenamente o interesse (ainda que teórico) em torno da linguagem e das técnicas associadas a ela. </td> </tr> |
Comparative Programming Languages – 2nd Edition</p> Muito mais denso que os anteriores, este livro traça um panorama das linguagens de programação mais relevantes, desde as primeiras tentativas de evoluir do código de máquina puramente numérico até os primeiros ambientes OO maduros. Para quem, como eu, trabalha a maior parte do tempo com Java, é muito esclarecedor ter um contato com fontes de inspiração como Ada e Modula-2 (além de C++, que eu já conhecia, mas também ajudou ver em perspectiva). E, independente da linguagem, aspectos como alocação de memória, passagem de parâmetros, escopo, tipagem e muitos outros são analisados em detalhe (do código fonte à execução final), considerando sempre o tripé performance-flexibilidade-confiabilidade. Ao contrário de boa parte da literatura do gênero, Comparative Programming Languages não requer um background matemático, ou mesmo conhecimentos extremamente avançados em programação. A terceira edição (abordada no site) engloba linguagens mais modernas, mas a que li tem um bom equilíbrio entre a perspectiva histórica e a análise computacional. |
Comments
krico
Lindo o post!
Aproveita e me esclarece. Minha visão existem 3 tipos de linguagens.
OO como por exemplo Java, Smalltalk, etc
Funcional como por exemplo C
e Lisp que não é funcional, mas sei ao certo o que é. É procedural?
Você viu que o OLPC (http://laptop.org) vai vir com um squeak!?
Chester
Que bom que você gostou.
Creio que o termo apropriado para C é "imperativa", e não "funcional". E ainda estou engatinhando nesse assunto de programação funcional, mas vamos tentar:
Pra começar, existem pelo menos duas interpretações do termo. Uma visão "acadêmica" consideraria que linguagens funcionais são aquelas em que se trabalha sobre um conjunto de definições (sob a forma de funções, por exemplo), que só são calculadas quando isso se faz necessário para resolver um problema proposto (e entra toda aquela história de cálculo lambda). Como bem coloca a Wikipedia (http://tinyurl.com/yu8y7y), elas enfatizam a aplicação de funções, enquanto que a programação tradicional (imperativa/OO) enfatiza as mudanças de estado.
Embora seja uma definição muito rica, acaba se tornando limitada em termos práticos, já que poucas linguagens atingem tal nível de abstração. Uma definição mais pés-no-chão trata como funcionais as linguagens onde as funções são "cidadãs de primeira classe", permitindo a sua manipulação de forma direta (e não simplesmente o call/evaluate, como acontece nas linguagens imperativas). Analogamente, podemos dizer que uma linguagem possui características funcionais se algumas de suas operações aplicam tratamento deste tipo a funções.
Sob esta ótica, Lisp pode ser considerado funcional (uma função é uma lista como outra qualquer, e elas podem ser manipuladas, calculadas, estendidas ou impostas sobre outras listas). Closures são exemplos tidos como características funcionais em Ruby (mesmo que Ruby esteja longe de ser um ambiente de programação puramente funcional). E praticamente qualquer linguagem moderna permite a recursão, que, quando apropriadamente definida, é uma abordagem puramente funcional para uma ampla gama de problemas.
Ajudou? Atrapalhou? :-)
Helton
A impressão que tenho é que o importante de aprender Funcional é muito mais pra vc aprender a pensar melhor na hora de programar alguma coisa. Depois que vc consegue entender um código Lisp/Scheme, com mapcar, etc, vc entende qualquer outra coisa.
No entanto, na prática (em meios comerciais, etc), o quanto isto é usado?
Vc acha que existe alguma linugagem "moderna" que tenha OO + funcional?
(Quando digo funcional, é quando vc pode usar mapcar, etc..)
(Ainda não me aventurei pra aprender Ruby.)
Quanto à guerra entre linguagens de programação, concordo que mais parece uma guerra "religiosa".
Acho que tudo depende da aplicação. Fora que, as tecnologias sempre mudam, é sempre bom ter os conceitos mais lógicos, pra aprender qualquer outra linguagem "brincando".
Chester
Helton,
É curioso notar que essas questões sobre uso prático, linguagens/implementações viáveis e tópicos assemelhados também surgiram quando o paradigma OO começou a sair da academia e aparecer no mundo corporativo. Não estou sugerindo que o paradigma funcional será absorvido com a mesma pervasividade, mas é interessante observar este paralelo.
Outra semelhança "social" com o OO na década de 80/90 é a aparente negação de conceitos tidos como fundamentais em computação (negação esta que torna muito difícil a transição para pessoas com mais tempo na área). No caso do OO, o conceito arraigado era a divisão clara entre programa e dados, e no da funcional é a computação centrada na mudança de estados.
Até onde sei, o uso em sistemas comerciais ainda é muito limitado (o caso do Google é emblemático, mas um pouco fora da realidade corporativa). Isso acontece porque uma das maiores vantagens do paradigma funcional é aproveitar sistemas massivamente paralelos(*) - que ainda são poucos e caros, mas a anunciada "explosão dos cores", sob o efeito da Lei de Moore, acena para um futuro onde "paralelizável" se torne uma meta tão importante quanto "escalável" ou "performático".
(*) é preciso estudar um pouco o assunto para entender essa relação, mas, resumidamente, tem a ver com a minimização do papel do estado (ambientes funcionais mais "puros" chegam a extremos tais como abrir mão do operador de atribuição). Esta minimização anula os chamados "efeitos colaterais", permitindo que operações que, num ambiente imperativo, dependiam da ordem de execução, possam ser executadas em paralelo.
Massa
0x0d2C
May your signals all trap
May your references be bounded
All memory aligned
Floats to ints rounded
Remember ...
Non-zero is true
++ adds one
Arrays start with zero
and, NULL is for none
For octal, use zero
0x means hex
= will set
== means test
use -> for a pointer
a dot if its not
? : is confusing
use them a lot
a.out is your program
there's no U in foobar
and, char (*(*x())[])() is
a function returning a pointer
to an array of pointers to
functions returning char
//autor desconhecido
Lucio
C# 3.0 (codename Orcas), por exemplo, vai ter expressões lambda, closures e coisas muito parecidas com mapcar. http://tinyurl.com/kjsp3.
Chester
Sobre LISP: http://xkcd.com/c224.html
Ronaldo Augusto Vasques de Sou
Só para constar eu escrevo compiladores e interpretadores a mais de vinte anos.
Achei este post muito interesssante e esclarecedor.
O que tenho a acressentar é que os paradigmas(modelos) de programação aqui apresentados não são os únicos existêntes porém(por razões historio´econômicas) são os mais utilizados.
Todos esses modelos evoluíram á partir dos primeiros microprocessadores onde a linguagem é conhecida como código de máquina; essa linguagem é de numérica binária, organizada por endereços inteiros continuos e seus respectivos valores, alguns registradores de estados, além de ser de difícil compreênção para nós humanos; caracteriza-se por sua linearida(estou falando dos primeiros processadores) ou seja apenas uma instrução por vez pode ser executada em sequüencia não existindo nenhum conceito de subrotina ou função. Para simplificar a programação muitos ciêntistas computacionais associavam uma tabela de mneumônicos(apelidos) para cada instrução de máquina...nascia o Assembly.
Esse Assembly, apesar de simplificar a vida de nossos acestrais programadores, era e ainda é muito improdutivo; então foram iniciada a procura por uma linguagem que pudesse ser convertida em código de máquina e que fosse de razoável compreeção. As linguagens ai descobertas mantinham as mesmas caracteristicas lineares do código de máquina porém tinham uma sintaxe muito mais clara(gaças a tipagem) e a essas linguagens chamamos de "linguagens imperativas"(C, ADA, Fortran, Forth).
As linguagems declarativas foram criadas na mesma época que as imperativas, a principar diferença é de que as linguagens declarativas não tentem imitar a estrutura dos processadores e sim buscar soluções para um problema baseado em um conjunto de premissas introduzidos pelo úsuário(Prolog, SQL, Mercury).
Já as linguagens funcionáis elas partem do modelo estruturado de programação onde todos os elementos que caracterizam linguagens imperativas e/ou declarativas estão presentes porém fora adicionado o conceito de funções, que nada mais é que uma subrotina do programa, identificada e que possa ser chamada a qualquer momento após sua declaração ou prototipagem e que possa retornar ou não um valor(Lisp, ECMAScript).
O Modelo orientado a objetos tende a trabalhar os dados e não o estado de funcionalidade da máquina, ele enfoca a estrutura dos dados assim como o comportamento dessas estruturas gerando assim uma identidade a qual é denominda classe e a implementação dessas classes chama-se objeto(SmallTalk).
Linguagens como Java, VC++, C#, Visual Basic ou Delphi são linguagens de difícil classificação pois são multiparadigmas.
E os atuáis sistemas operacionais trabalham com um paradigma chamado de linguagem simbólica onde cada simbolo corresponde a uma ação ou objeto; esse grupo de símbolos pode ser redefinido a qualquer momento pelo usuário fazendo com que não exista um padrão uniforme de valores definidos para os símbolos(Windows, MacOS, X11)
Nei
Gostaria de saber sobre a paradigma do Delphi, você falou que ele é classificado como multiparadigma. Mas como assim, ele é "metade" imperativo e "metade" orientado-objeto ou é mais OO que imperativo ou é mais imperativo que OO...
E se puder me ajudar em quais são suas características e quais linguagens o influenciou e quais ele influenciou, ficarei grato também.
Aguardo respostas, Valeu!
Romaldo Augusto Vasques de Sou
O Delphi é uma ferrementa de desenvolvimento baseada no Pascal que é uma linguagem imperativa.
Tenha em mente que a linguagem Pascal fornecida com os compilados Borland (Turbo Pascal) usam algumas melhorias derivadas da liguagem Modula, que é descendente do Pascal; e a introdução a orientação a objetos.
Já o Delphi incorpora as melhorias contidas em seu predecessor e um excelente suporte a OO e OE. Mas ainda é uma linguagem imperativa pois toda a ação ainda depende do velho e imperativo "PROGRAM".
No geral(não é regra) com o Delphi nós provemos ações a serem consumidas como eventos(OnClick, OnMouseOver...), porém esse sistema de eventos não é a unica forma de interagir com a VCL e a VCL não é a única maneira de gerar aplicações.
Se você clicar no menu Project -> View Source irá abrir uma janela contendo a fonte de sua aplicação. Lá encontraremos a velha estrutura imperetiva Pascal "PROGRAM"
e o bloco(em uma forma bem simplista):
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
Que serve como ponto de entrada para a VCL. Se você promover alterações dentro deste bloco como:
{$APPTYPE CONSOLE}
var Texto: string;
begin
Texto := 'Programinhas Pascal são bem aceitos aqui!';
Writeln(Texto);
end.
Qualquer fonte imperativa em Pascal pode ser utilizada.
Fazendo chamadas a Windows API pode-se criar aplicações wimdows que não usem a VCL.
Hoje o Delphi já pode utilizar recursos .NET, porém o modelo continua o mesmo o que possibilita a utilização de recursos VCL com .NET.
Caso haja interesse seu em POO puram, o SmallTalk é uma liguagem estritamente OO.