O Essencial sobre Linguagens de Programação Artur Miguel Dias Março 2006 FCT/UNL Índice Um Pouco de História Computação, Algoritmos e Programas Critérios de avaliação de linguagens Paradigmas de Programação Conceitos básicos 3 13 21 27 31 Um Pouco de História: Linguagem Máquina Datas No final da década de 40, não existiam alternativas ao uso de linguagem máquina. Principais características Instruções especificadas por meio de códigos numéricos, em binário. Utilização directa de endereços absolutos nos programas. Um Pouco de História: Linguagem Máquina Discussão Programas difíceis de escrever e quase impossíveis de ler. Grande facilidade em cometer erros. Os programas só funcionam no tipo específico de hardware para que foram escritos. Dificuldade em inserir ou remover instruções nos programas, por causa dos endereços absolutos (a instrução nop ajuda um minorar um pouco este problema). Um Pouco de História: Assemblers Datas Assemblers começaram a surgir no início dos anos 50. Características mais importantes Permitem atribuir nomes a códigos de operação (mnemónicas), a localizações de memória (etiquetas) e a constantes. Um tradutor – chamado assembler – traduz instruções assembler em instruções máquina. Um programa pode conter directivas que não dão origem a código: declaração de constantes, por exemplo. Um Pouco de História: Assemblers Discussão Os aspectos negativos mais dramáticos da linguagem máquina ficam minorados. No entanto os programas continuam a ser difíceis de escrever e de ler. Os programas também continuam a ter de ser escritos para arquitecturas particulares. Mas já se observam algumas “sementes” das futuras linguagens de programação. Um Pouco de História: Assemblers Exemplo: Programa “factorial” escrito para o Pentium .file "fact.c" .section .rodata .LC0: .string "> " .LC1: .string "%d" .LC2: .string "fact(%d) = %d\n" .text .globl main .type main, @function pushl %ebp movl %esp, %ebp subl $40, %esp andl $-16, %esp movl $0, %eax addl $15, %eax addl $15, %eax shrl $4, %eax sall $4, %eax subl %eax, %esp movl $.LC0, (%esp) call printf leal -12(%ebp), %eax movl %eax, 4(%esp) movl call movl movl jmp .L2 .L3: movl imull movl leal addl .L2: movl cmpl jle .L3 movl movl movl movl movl call movl leave ret .size $.LC1, (%esp) scanf $1, -4(%ebp) $1, -8(%ebp) -4(%ebp), %eax -8(%ebp), %eax %eax, -4(%ebp) -8(%ebp), %eax $1, (%eax) -12(%ebp), %eax %eax, -8(%ebp) -12(%ebp), %edx -4(%ebp), %eax %eax, 8(%esp) %edx, 4(%esp) $.LC2, (%esp) printf $0, %eax main, .-main Um Pouco de História: Fortran Datas Anunciado por John Backus da IBM em 1954. A implementação inicial, designada Fortran I, ficou disponível em 1957, com compiladores para IBM 704 e IBM 709. Prometia Eficiência dos programas escritos em assembler. Simplificar a escrita de programas mediante o uso de notação matemática (Fortran = “FORmula TRANslator”). Reduzir os erros de programação. Um Pouco de História: Fortran Características mais importantes Instruções de controlo pobres e influenciadas pelas instruções da máquina IBM 704. Necessário recorrer muito à instrução goto. Suporte para inteiros, reais e arrays, mas não para registos. Suporte para variáveis estáticas. Impossível criar novas variáveis em tempo de execução. Suporte para subrotinas não recursivas. Um Pouco de História: Fortran Discussão Depois do Fortran I foram surgindo versões melhoradas: Fortran II em 1958, Fortran IV em 1962, Fortran 77 em 1978 e Fortran 90 em 1990. Tornou-se na primeira linguagem de programação popular e, a partir do início dos anos 60, mudou de forma revolucionária a forma como os computadores eram usados. Ainda é bastante usada actualmente em aplicações de cálculo numérico! Passou a ser possível escrever programas portáveis! Um Pouco de História: Fortran Exemplo: Programa “factorial” em Fortran 10 20 READ 10,I FORMAT(I3) J=1 DO 20 K=1,I J=J*K CONTINUE PRINT 10,J STOP Um Pouco de História Outras linguagem pioneiras (início anos 60) Algol 60: primeiro passo em direcção à sofisticação das linguagens modernas. Lisp: dominou as aplicações de IA durante 25 anos. Cobol: linguagem das empresas e do DoD. Basic: muito simples de aprender, destinada a não especialistas. Computação, Algoritmos e Programas Computação Significa: processamento automático de informação. É a actividade realizada pelos computadores. O objectivo da informática é estudar a computação e formas úteis de tirar partido da computação (nomeadamente para resolver problemas importantes). Computação, Algoritmos e Programas Facetas da computação Faceta interna: a informação é codificada usando símbolos (e.g. bytes), sendo realmente a computação uma actividade de manipulação e transformação automática de símbolos … Faceta externa: … mas, geralmente, as computações também estabelecem um diálogo interactivo com o ambiente exterior (constituído por humanos e por outras máquinas). Computação, Algoritmos e Programas Automatismos e sua especificação Qualquer computação é realizada de acordo com regras estabelecidas antes desse processamento se iniciar. É isso que significa o processamento ser automático. Daí a necessidade que especificar as computações de forma rigorosa e exaustiva, prevendo todas as eventualidades. Computação, Algoritmos e Programas Algoritmo Programa É um conjunto de regras abstractas (uma espécie de receita) que determinam, passo a passo, como uma computação vai decorrer. É uma descrição possível dum algoritmo. Um programa serve para implementar um algoritmo. Linguagem de programação É uma notação para escrever programas, ou seja para implementar algoritmos. Computação, Algoritmos e Programas Exemplo de algoritmo: algoritmo de Euclides – mdc(m,n) Usar dois contadores x e y e inicializar x com m e y com n. Se x > y então x recebe x - y Se x < y então y recebe y - x Repetir os dois passos anteriores até que os valores de x e y fiquem iguais. Quando isso acontecer, esse é o resultado final. Computação, Algoritmos e Programas Implementação em C do algoritmo anterior #include <stdio.h> int main() /* Implementação do algoritmo de Euclides */ { int m, n, x, y ; printf(">> ") ; scanf("%d %d", &m, &n) ; x = m ; y = n ; do { if( x > y ) x = x - y ; else if( x < y ) y = y - x ; } while( x != y ) ; printf("mdc(%d,%d) = %d\n", m, n, x) ; return 0 ; } Computação, Algoritmos e Programas Algoritmos A principal motivação para se usarem máquinas para executar algoritmos é a grande velocidade de execução que elas permitem. Os algoritmos mais antigos que se conhecem devem-se aos Babilónios (3000AC-1500AC). Os seus livros de Matemática eram acima de tudo receitas sobre como efectuar os cálculos para resolver determinados problemas. Esses algoritmos eram para executar “à mão”. Computação, Algoritmos e Programas Três questões importantes sobre computação e linguagens. Existem limites para a computação? Sim, realmente existem problemas com solução para os quais não se consegue escrever qualquer algoritmo que descubra essa solução. Existe alguma linguagem de programação que permita implementar todos os algoritmos que se possam imaginar? Sim, qualquer linguagens normal permite isso. Do ponto de vista do poder computacional, todas as linguagens normais são equivalentes. Critérios de avaliação de linguagens Se todas as linguagens têm idêntico poder computacional, estão porque razão existem tantas linguagens de programação (milhares!) e se estão constantemente a criar novas? Pelas seguintes razões: Uma linguagem deve ajudar o programador a exprimir de forma clara e directa os seus objectivos. De acordo com este critério há linguagens melhores e piores (compare o Fortran com o C++, por exemplo) e é sempre possível ir melhorando. Há linguagens que favorecem uns domínios de aplicação relativamente a outros. Critérios de avaliação de linguagens Legibilidade Possibilidade de, através do exame de um programa escrito por outra pessoa, de seguir a sua lógica e descobrir a presença de erros. Para isso são importantes os seguintes factores: Simplicidade (permite conhecer a linguagem toda); Ortogonalidade (todas as combinações dos mecanismos primitivos são válidas); Estruturas de controlo de qualidade; Estruturas de dados de qualidade; Sintaxe racional (com palavras reservadas, construções diferentes para mecanismos diferentes). Critérios de avaliação de linguagens Redigibilidade Possibilidade de expressar um problema de forma natural, sem que a atenção do programador seja desviada por detalhes ou "truques" da linguagem. Para isso são importantes os seguintes factores: Simplicidade (menos erros); Ortogonalidade (não se perde tempo a pensar em excepções às regras gerais); Suporte para abstracção (ajuda a dominar a complexidade dos problemas); Expressividade (construções simples para as operações frequentes). Critérios de avaliação de linguagens Segurança Possibilidade de escrever programas que dêem garantias de que atingem o efeito desejado. Para isso são importantes os seguintes factores: Sistema de tipos estático (detecta todas as incompatibilidades de tipo em tempo de compilação); Tratamento de excepções (permite a tomada de medidas correctivas em situações inesperadas); Ausência de sinonímia (é perigoso uma mesma entidade ser conhecida por dois nomes diferentes). Critérios de avaliação de linguagens Eficiência Actualmente a eficiência já não é mais medida apenas com base velocidade de execução dos programas e na economia no uso da memória. Considera-se também o esforço necessário para produzir os programas e o esforço necessário para os manter. Critérios de avaliação de linguagens Facilidade em escrever programas grandes Modularidade: Possibilidade de escrever um programa por partes, para melhor o estruturar e compreender. Componentes: Possibilidade de incorporar num programa componentes “pronto-avestir” e substituir certas componentes do programa por outras melhores no futuro. Paradigmas de Programação Já sabemos que computação significa processamento automático de informação, mas esta noção é demasiado vaga. Podemos interrogar-nos sobre quais os mecanismos concretos através dos quais esse processamento se efectua. Na verdade, uma linguagem não pode deixar de se comprometer com algum conjunto mecanismos primitivos para processar informação. Ao efectuar essa escolha, a linguagem adere a um paradigma de programação particular. É surpreendente a grande variedade de paradigma de programação que têm sido inventados. Paradigmas de Programação Os alunos da LEI são expostos a cinco paradigmas de programação: Paradigma imperativo Conceitos de base: estado, atribuição, sequenciação Linguagens: Basic, Pascal, C, Assembler. Paradigma funcional Conceitos de base : função, aplicação, avaliação Linguagens: Lisp, ML, OCaml, Haskell. Paradigma lógico Conceitos de base : relação, dedução Linguagens: Prolog. Paradigma orientado pelos objectos Conceitos de base : objecto, mensagem Linguagens: C++, Java, Eiffel. Paradigma concorrente Conceitos de base : processo, comunicação (síncrona ou assíncrona) Linguagens: Occam, Ada, Java. Paradigmas de Programação Cada paradigma de programação determina uma forma particular de abordar os problemas e de formular as respectivas soluções. Cada paradigma de programação dá origem a um estilo particular de linguagens de programação. Paradigmas de Programação O grau de sucesso dum programador depende em parte da colecção de paradigmas que domina e da sua arte em escolher o mais indicado para analisar e resolver cada problema. A maior parte das linguagens em uso suportam mais do que um paradigma. A tendência multi-paradigma das linguagens modernas tem sido crescente. Por exemplo, o C++ suporta os paradigmas imperativo e orientado pelos objectos. O Java suporta os paradigmas imperativo, orientado pelos objectos e concorrente. Conceitos básicos: Literais Um literal é uma expressão constante que denota um valor particular. Exemplos em C++: 0, 5, -127 56.7, -33.4e32 ”ola”, ”ole” false, true Conceitos básicos: Expressões São entidades geralmente compostas que podem ser avaliadas para produzir um valor. Exemplos em C++: 5+x 56.7 * 3.4 ”ola” + ”ole” x+3>y-4 Conceitos básicos: Definições Uma definição associa um nome a uma entidade. O seguinte exemplo contém três definições: a primeira associa o nome f à função apresentada, a segunda associa x à constante 10 e a terceira associa y a uma posição de memória nova. void f() { const int x = 10 ; double y ; … } Conceitos básicos: Âmbito O âmbito duma definição é a zona do programa em que uma definição está activa. Por exemplo, o âmbito da variável y é a porção do código que começa na linha da sua definição até ao final a função (assumindo que o y não é redefinido no interior – pois um âmbito pode ter “buracos”). void f() { const int x = 10 ; double y ; … } Conceitos básicos: Extensão duma variável A extensão duma variável é o período da execução do programa durante o qual a variável pode ser acedida. Há três categorias: Variáveis estáticas (extensão = toda a vida do programa) Variáveis automáticas (extensão = tempo de vida da função na qual estão declaradas). Variáveis dinâmicas (criadas com new e apagadas com delete e acedidas através de apontadores; o uso destas primitivas determinam a extensão duma variável dinâmica). Conceitos básicos: Âmbito e extensão Problema: qual o âmbito e qual a extensão da variável count que ocorre dentro da função g? void g() { static int count = 0 ; count++ ; … } Conceitos básicos: Parametrização Parametrizando parte dum programa num nome obtém generalidade. Somar 100 à variável y: y := y + 100 Função que permite somar qualquer v a y: void add(int v) { y := y + v ; } Quais as formas de parametrização disponíveis na linguagem C++? O Essencial sobre Linguagens de Programação Fim