13 março 2010

O Delphi é o novo Cobol?

Depois de um debate em um fórum, fiquei pensando: será que o Delphi terá o mesmo destino de outras linguagens que foram líderes de mercado em suas épocas e depois sumiram, deixando um rastro de sistemas legados?

Acho que isso é o que acontece com qualquer linguagem bem sucedida. O Delphi foi um dos produtos mais famosos da finada Borland, que antes disso já tinha entrado para a história da informática com o Turbo Pascal. Acredito que o Brasil foi um dos maiores mercados do Delphi, já que essa linguagem acabou sucedendo o Clipper como padrão para o desenvolvimento de sistemas comerciais por aqui.

A linguagem era simples e poderosa (para a época), mesmo que um pouco verborrágica demais (afinal, era baseada em Pascal). Incluía uma orientação a objetos levemente parecida com Java (baseada em classes de herança simples, herança múltipla de interfaces, separação entre tipos primitivos e classes e, ainda, propriedades com getters e setters). O IDE era parecido com o do maior concorrente, o Visual Basic: muita facilidade para desenho das janelas e dezenas de componentes incluídos. Suporte a depuração, um compilador muito rápido (marca registrada da Borland) e a possibilidade de criar executáveis que rodavam sem a necessidade de runtimes e DLLs.

Durante boa parte da década de 90 essa foi a linguagem preferida para o desenvolvimento dos gloriosos "sisteminhas" como controle de estoque e frente de caixa. A grande facilidade de uso permitiu que programadores sem muita experiência criassem sistemas complexos. A possibilidade de criar componentes facilmente distribuíveis também favoreceu a criação de um grande mercado de componentes que davam acesso a dispositivos, geravam relatórios e manipulavam vários formatos de arquivos (só para ficar nos mais comuns).

Essa facilidade toda também teve seu lado negativo: desenvolver sistemas complexos é... complexo e quando feito por programadores sem o conhecimento necessário leva a abusos (gambiarras) e falhas na implementação. Programar é mais que desenhar janelas e arrastar componentes e a falta de qualidade nos sistemas feitos dessa maneira acabou contaminando a própria linguagem Delphi com uma fama de "coisa de amadores" (no mau sentido).

Com o tempo e o aparecimento de outras linguagens, o Delphi começou a mostrar as suas limitações. A falta de um bom gerenciamento automático de memória, a divisão entre tipos primitivos e a hierarquia de classes, a inexistência de referências que trabalhassem com esses dois "supertipos" de valores, a inflexibilidade da biblioteca padrão de componentes e os próprios bugs do IDE Delphi são exemplos de problemas que eram menores ou inexistentes na concorrência.

A enorme dificuldade da Borland em gerenciar o produto Delphi no mercado de linguagens de programação e em desenvolver a ferramenta de modo a acompanhar a evolução da programação acabou enterrando a linguagem. A falta de um suporte razoável para programação web também pesou nesse caminho. O Delphi ainda é muito usado no Brasil, mas cada vez mais empresas migram para linguagens mais modernas como Java e C#. De certa forma, dá pra dizer que o Delphi já é o novo Cobol.

E agora, qual será (é) o novo Delphi?

25 outubro 2006

Lógica de Programação 10

Neste tópico vamos ver alguns dos operadores da nossa linguagem. Vamos começar com os operadores matemáticos:

(3 + 5) * 2 - (10 / 2)
Como você pode ver, os operadores são muito parecidos com aqueles que a gente aprende na escola: + é soma, - é subtração, * (asterisco) é multiplicação e / (barra) é divisão. Os parênteses funcionam como na matemática, mudando a ordem em que as expressões são avaliadas. Se não há parênteses, a ordem padrão é utilizada: multiplicação e divisão primeiro, depois soma e subtração.

O resultado de operadores matemáticos, que precisam de um número de cada lado, é sempre outro número: primeiro 3 + 5 é calculado, depois 8 * 2, então 10 / 2 (por causa do parênteses) e finalmente 16 - 5, resultando em 11.

Outro tipo de operadores são os de comparação:
3 == 5
3 != 5
3 < 5
1 <= 1
2 >= -5
Esses operadores precisam de um número de cada lado (por enquanto) e retornam não um número, mas um valor booleano. Valores booleanos podem apenas ser falso ou verdadeiro. Nesse exemplo, 3 é diferente de 5, então 3 == 5 (o operador para igual) retorna falso e 3 != 5 (o operador para diferente) retorna verdadeiro. Como 3 é menor que 5, 3 < 5 também retorna verdadeiro. Um é menor ou igual a 1, então 1 <= 1 também é verdadeiro, assim como 2 >= -5.

O último tipo de operador que vamos ver agora são os operadores lógicos:
falso ou verdadeiro
não verdadeiro e 3 > 2
salário > 5 * salário mínimo e idade < 30 e não solteiro
Alguns desses operadores nós já vimos, sempre precisando de um valor booleano de cada lado (com exceção do operador não). O operador ou retorna verdadeiro se qualquer um dos valores é verdadeiro (no exemplo, falso ou verdadeiro retorna verdadeiro). O operador não inverte o valor booleano: se era verdadeiro, retorna falso e vice-versa. O operador e retorna verdadeiro só se os dois valores são verdadeiros (o exemplo retorna falso, já que não verdadeiro é falso). A terceira linha mistura todos os operadores que nós já vimos: retorna verdadeiro se a variável salário tem valor maior que 5 vezes o salário mínimo (outra variável) e ao mesmo tempo idade é menor que 30 e ao mesmo tempo a variável solteiro é falsa.

05 outubro 2006

Lógica de programação 9

No último post nós vimos como trocar um número máximo de lâmpadas, e também como trocar apenas as lâmpadas queimadas dentro desse número máximo. Isso é o que nós conseguimos até agora:

trocas = 0
enquanto trocas < 10 faça
se não existir lâmpada queimada então
interrompa
fim se
// todo aquele código que troca uma lâmpada
trocas = trocas + 1
fim enquanto
Como você pode ver, estamos limitando o número de trocas na condição da repetição enquanto que dentro do bloco de código repetido nós usamos um condicional para interromper a repetição quando terminamos de trocar as lâmpadas queimadas. Vamos ver o que acontece se trocarmos as condições de lugar:
trocas = 0
enquanto existir lâmpada queimada faça
se trocas >= 10 então
interrompa
fim se
// todo aquele código que troca uma lâmpada
trocas = trocas + 1
fim enquanto
Veja como as condições se inverteram. Isso aconteceu porque a condição do enquanto deve ser verdadeira durante toda a repetição, até que fica falsa quando a repetição deve terminar; por outro lado, a condição do condicional é falsa durante toda a repetição, ficando verdadeira para sinalizar o fim das trocas de lâmpadas. Se você simular esse código vai descobrir que ele faz exatamente a mesma coisa que o anterior.

Será que existe outra maneira de fazer isso? Claro: nós podemos unir essas duas condições numa expressão só, porque no fundo elas servem para dizer "continue repetindo... continue repetindo... pare!". Se é assim, nós podemos colocá-las no nosso enquanto e mandar aquele condicional passear:
trocas = 0
enquanto existir lâmpada queimada e trocas < 10 faça
// todo aquele código que troca uma lâmpada
trocas = trocas + 1
fim enquanto
Para fazer isso, usamos uma nova palavra reservada: e. Esse tipo de palavra chave (outro nome para palavra reservada) também é conhecido como operador, porque pega expressões, fazendo alguma operação com elas, e retorna o resultado da operação. O operador e retorna um valor verdadeiro se as expressões da cada lado dele (direito e esquerdo) forem verdadeiras ao mesmo tempo. Esse código faz a mesma coisa que os dois anteriores, mas de uma maneira mais elegante e resumida.

Na próxima parte vamos conhecer outros operadores da nossa linguagem.

03 outubro 2006

Lógica de programação 8

Nós já sabemos trocar todas as lâmpadas de uma sala usando repetição (se não lembra veja a parte 6 dessa série), mas digamos que o SINDETROL (Sindicato dos Estagiários Trocadores de Lâmpadas) tenha feito um acordo que limita as trocas de lâmpadas a 10 por dia. Nesse caso, nós vamos ter que contar as trocas de lâmpadas e parar quando chegarmos na décima troca. Para fazer isso podemos usar uma variável:

trocas = 0
enquanto trocas < 10 faça
// todo aquele código que troca uma lâmpada
trocas = trocas + 1
fim enquanto
Vamos tentar entender o que está acontecendo. No começo, o valor inicial da variável trocas é zero, porque ainda não trocamos lâmpadas hoje. Como zero é menor que 10 o código que troca uma lâmpada é executado e trocas é somado com 1. Como 1 ainda é menor que 10, trocamos mais uma lâmpada e trocas passa a ser 2. Isso acontece até que trocas está valendo 9, porque já trocamos 9 lâmpadas, e o código de troca de lâmpadas é executado pela última vez. Depois disso, trocas é incrementado para 10. Como 10 não é menor que 10 a repetição pára e o estagiário vai tomar um cafezinho. Note que só podemos incrementar o valor de trocas depois que realmente fazemos uma troca. Pronto. Fim do tópico.

Não! Como você deve lembrar, a repetição da parte 6 tinha como condição ainda existir alguma lâmpada queimada para ser trocada. Agora estamos trocando 10 lâmpadas sem nem ver se elas estão queimadas ou não! Vamos tentar consertar isso com um comando novo:
trocas = 0
enquanto trocas < 10 faça
se não existir lâmpada queimada então
interrompa
fim se
// todo aquele código que troca uma lâmpada
trocas = trocas + 1
fim enquanto
Agora, enquanto a repetição limita o número de trocas a 10, o condicional que colocamos logo no começo da repetição trata de interromper a repetição se não tiver mais lâmpadas queimadas. Se as lâmpadas queimadas acabaram o comando interrompa cancela a repetição, fazendo com que o computador execute o comando seguinte ao fim da repetição.

Mas essa não é a única forma de fazer isso (dica: o que acontece se usarmos o mesmo mecanismo, mas com as condições da repetição e do condicional trocadas?). Na próxima parte, vamos ver variações desse exemplo.

02 outubro 2006

Lógica de programação 7

Como eu prometi, hoje vamos aprender a contar. Quer dizer, espero que você já saiba contar: o que nós vamos aprender é como fazer o computador contar. Para fazer isso, nós vamos usar outro conceito importante, chamado variável. Uma variável é um espaço na memória do computador que pode guardar um dado qualquer. As variáveis têm nomes, para que o computador saiba (e o programador também!) de que espaço na memória que a gente está falando. Na nossa linguagem nós criamos uma nova variável quando damos um valor para ela pela primeira vez:

x = 10
Isso faz com que o computador reserve um espaço na memória para guardar o valor da variável x e ponha o valor 10 nesse espaço. Vamos criar mais variáveis:
y = 5
x = 11
soma = x + y
salário = 1654.32
salário anual = salário * 12
média = (4 + 5 + 2 + 3.14159) / 4
Na primeira linha criamos uma nova variável y com o valor 5. Assumindo que esse exemplo é a continuação do outro, mudamos o valor da variável x, que era 10 e passou a ser 11 (no mesmo espaço de memória em que ela estava antes, porque ela já existia quando mudamos o seu valor). Também criamos uma variável soma com o resultado da soma de x com y: o valor inicial de soma é 16. A variável salário tem um valor real, em vez de ser inteiro como nos casos anteriores. Note que na nossa linguagem o separador de casas decimais é o ponto e não a vírgula; a grande maioria das linguagens de programação usa esse formato, que não por acaso é como os americanos escrevem os números deles. A variável salário anual tem o valor de salário multiplicado por 12 (19851.84). Os parênteses funcionam como na matemática: a variável média tem a soma dos 4 valores divida por 4 (3.5353975).

Veja que nesses exemplos eu só usei o valor de uma variável depois de ter dado um valor para ela. Não importa qual a linguagem, é sempre importante garantir que a variável tem valor antes de começar usar o valor dela. Algumas linguagens dão um valor padrão (zero, por exemplo); em outras o computador avisa que você esqueceu de definir um valor inicial; outras não ligam pra isso e deixam o pepino pra você (pepino porque você não tem como saber o que você vai encontrar na memória). Você pode descobrir isso lendo a documentação ou o manual da linguagem.

Mas o computador ainda não está contando! Cadê? Cadê a contagem? Calma, esse tópico foi só a vaselina. No próximo vai.

28 setembro 2006

Indentação

Se você está acompanhando os posts sobre lógica de programação, já deve ter notado que os textos têm um formato característico. Além da sintaxe da nossa linguagem de programação, isto é, da ordem em que as palavras reservadas têm que aparecer, também existe um certo padrão nos espaços que são usados no começo de cada linha. Esses espaços no início de cada linha são chamados de indentação. Na maioria das linguagens, inclusive na nossa, a indentação não faz parte da sintaxe: você pode usar a indentação que quiser, inclusive nenhuma, ou colocar espaços nos lugares que você quiser, que o significado do programa não muda.

Então para que serve a indentação? A indentação serve como um guia visual para nós, programadores humanos. Deixa o código fonte do programa mais organizado, mais fácil de ler, entender e modificar. Veja um exemplo altamente didático, sem indentação:

enquanto carros andando na rua faça
espere
olhe para um lado
olhe para o outro lado
fim enquanto
enquanto não chegar ao outro lado faça
se pessoa na frente então
desvie
senão
dê um passo
fim se
fim enquanto
Confuso, não? Agora com a indentação, colocando os blocos de código dentro das repetições e dos condicionais um nível de indentação para a direita (inclusive quando existe um bloco dentro do outro):
enquanto carros andando na rua faça
espere
olhe para um lado
olhe para o outro lado
fim enquanto
enquanto não chegar ao outro lado faça
se pessoa na frente então
desvie
senão
dê um passo
fim se
fim enquanto
Muito melhor. Tradicionalmente, a indentação era feita com tabulações (tecla Tab), com uma tabulação para cada nível. O problema é que existem alguns estilos de indentação que misturam espaços e tabulações, e quando se misturam os dois da maneira errada o resultado é uma bagunça feia de se ver. Para tentar evitar esse problema, virou moda usar só espaços para fazer a indentação: 8 ou, mais recentemente, 4 espaços para cada nível de indentação. Realmente não interessa muito o estilo a ser usado, desde que se use indentação (pode valer pontos extras nos trabalhos da universidade) e o estilo se mantenha no código fonte inteiro (é muito feio ficar trocando de estilo no meio do texto).

27 setembro 2006

Lógica de programação 6

Tudo bem, o condicional é muito divertido e tudo mais, mas e se eu for um estagiário trabalhando numa sala grande com muitas lâmpadas? Preciso copiar e colar esse código pra cada lâmpada maldita? Não, pequeno gafanhoto. É aí que entra outro conceito importatíssimo da lógica de programação: a repetição. Existem várias formas de repetição, mas todas são variações dessa:

enquanto condição faça
ações
fim enquanto
Isso faz com que o computador verifique a condição: se ela for verdadeira, ele executa as ações e verifica a condição de novo, para executar as ações de novo se ela continuar verdadeira, para verificar a condição de novo... Enfim, acho que já deu pra entender. Da mesma forma que no condicional, depois que o computador percebe que a condição ficou falsa e sai da repetição, ele não volta pra ela só porque a condição ficou verdadeira de novo. A única forma de repetir a repetição é colocar uma repetição dentro da outra. Vamos usar uma repetição na troca da lâmpada:
enquanto existir lâmpada queimada faça
se lâmpada muito alta então
por escada em baixo da lâmpada
subir na escada
remover lâmpada queimada
colocar lâmpada boa
descer da escada
guardar escada
senão
remover lâmpada queimada
colocar lâmpada boa
fim se
fim enquanto
Bonito, não? Num próximo post vamos deixar a coisa mais interessante e começar a contar.

Lógica de programação 5

Se você prestou atenção no condicional do último post, viu que eu destaquei algumas das palavras do código da troca da lâmpada. Aquelas são palavras com significado especial na nossa linguagem de programação. Todas as linguagens de programação têm palavras especiais, conhecidas como palavras reservadas, que indicam ao computador o que tem que ser feito. Essas palavras têm que ser colocadas numa ordem definida para que o computador possa entendê-las: é a sintaxe da linguagem, o formato em que o texto deve aparecer. Elas são reservadas porque são usadas pela linguagem: você não pode usá-las para outras coisas porque isso confunde o computador. Essa é a sintaxe do condicional, sem e com senão, respectivamente:

se condição então
ações (se a condição for verdadeira)
fim se

se condição então
ações (se a condição for verdadeira)
senão
ações (se a condição for falsa)
fim se
É bom lembrar que as ações são executadas apenas se a condição for verdadeira quando o computador estiver testando o condicional. O computador vai executando um comando depois do outro, na ordem em que foram escritos: se depois que o computador já tiver passado pelo condicional a condição se tornar verdadeira, isso não influi em nada nesse ponto do código — o computador não retorna a esse condicional só porque a condição mudou.