Por que eu devo ler este artigo:Neste artigo veremos porque é tão importante estudar os conceitos relacionados às linguagens de programação. Além disso, iremos fazer uma análise completa da Delphi Language através de uma lista de critérios pelos quais podemos fazer um julgamento da linguagem.

Serão feitas análises referentes a Legibilidade, Capacidade de Escrita e Confiabilidade da linguagem, afim de descobrir quais seus pontos fortes e fracos.

Por fim, veremos os itens que influenciam no custo de adoção de determinada linguagem para o desenvolvimento de sistemas.

A história do Delphi começa em 1970 quando foi lançada a linguagem procedural Pascal, que herdou diversas características do ALGOL. Na década de 80 se popularizou através do Turbo Pascal e na década de 90 surgiu o conceito do pascal orientado a objetos (Object Pascal).

Em 1993 a Borland iniciou o desenvolvimento de um projeto para a criação de um ambiente visual para criar aplicações Windows utilizando a linguagem Object Pascal, que foi batizado de Delphi e lançado no ano de 1995.

O arquiteto do projeto e que ficou conhecido como “pai” do Delphi foi Anders Heilsberg (também criador da linguagem C#). Desde o início, Delphi sempre foi pioneiro em tecnologias para o desenvolvimento de softwares, como conexão com banco de dados, programação Orientada a Objetos e ambiente de desenvolvimento rápido (RAD - Rapid Application Development).

A versão 2 do Delphi coincidiu com o Windows 95 e o desenvolvimento para 32 bits, mas como ficamos acostumados, Delphi era totalmente compatível com versão 16 bits. Na versão 3, Delphi inovou mais uma vez, pois foi a primeira ferramenta a ter suporte para criar aplicações multicamadas em um ambiente RAD.

O Delphi 4 trouxe suporte aos mais recentes padrões de mercado naquele momento: CORBA, ORACLE 8, além de criação de controles ActiveX/Active Forms.

O Delphi 5 inovou com o suporte a manipulação fácil de arquivos XML, além de suporte a nova tecnologia de acesso a dados: ADO. Além disso, apareceram novas ferramenta como o TeamSource para controle de versão.

A versão 6, trouxe suporte a Web Services, além de BizSnap, DataSnap e WebSnap. Juntamente com a versão 6, nasceu o Kylix, primeira ferramenta RAD para Linux, para criação de aplicativos cross-plataform. No Delphi 7 aparecem os primeiros indícios de suporte a nova plataforma que estava nascendo, o .NET.

Nessa versão, temos um compilador para .NET, mas o ambiente do Delphi ainda não oferecia suporte, teríamos que criar aplicações totalmente manuais, sem as facilidades de componentes e modelagem rápida. Nesta versão não temos mais o Object Pascal como linguagem, mas sim a Delphi Language, mudança de nome para fins comerciais.

O Delphi 8 suportava apenas aplicações .NET, o que confundiu alguns desenvolvedores e seu IDE mudou drasticamente, sendo mais pesado e consumindo muita memória.

A versão 2005 do Delphi prometia ser a primeira ferramenta a ter ambiente de desenvolvimento para Win32 e .NET (Delphi e C#). Teve início a arquitetura ALM desenvolvida pela Borland, onde temos ferramentas para controlar todo o clico de vida do projeto, desde requisitos até a finalização do mesmo.

O Delphi 2006 foi a última versão da Borland, que juntamente com o Delphi 2007, trouxe algumas novidades no desenvolvimento para .NET e Win32, com a criação de novos componentes para suporte ao Windows Vista e suporte a novas versões do .NET Framework.

No Delphi 2009, já tivemos modificações significativas, onde não existe mais o mesmo ambiente para Win32 e .NET.

A CodeGear, então detentora do Delphi, em uma solução radical (no olhar de alguns desenvolvedores), aproveitou que o Visual Studio (principal concorrente) “liberou” o seu ambiente de desenvolvimento (shell) para outras linguagens e utilizou o mesmo e começou a disponibilizar o Delphi Prism.

Imagine desenvolver em Pascal (na verdade se chama Oxygene, da RemObjects, parceira da Embarcadero), usando o Visual Studio. Foi um verdadeiro choque na comunidade.

Na defesa da Embarcadero, a vantagem de usar o ambiente do Visual Studio, seria que o desenvolvedor estaria sempre com a versão mais recente do .NET Framework, além de tecnologias como LINQ, WPF, ASP.NET, Windows Forms e etc.

Mesmo assim, a versão Win32 do Delphi 2009 trouxe novidades como suporte a Generics, Métodos Anônimos e Ribbon. No Delphi 2010, tivemos o suporte a criação de aplicações touchpad, para criar interfaces onde o usuário interage com a mesma usando toque no monitor, uma grande novidade.

Na sequência temos as versões XE e XE2. O XE trouxe suporte ao Windows Azure (desenvolvimento em nuvens) e novidades no DataSnap. O XE2 trouxe novidades significativas como suporte a desenvolvimento de projetos em 64 bits, aplicações multiplataformas para Windows e OSx (Mac), criação de aplicações 3D e HD com um framework chamado FireMonkey e um recurso de LiveBindings para a ligação de dados aos componentes, entre outros.

Na versão XE3 tivemos o lançamento da interface Metropolis UI, para desenvolvermos interfaces gráficas semelhantes às existentes no Windows 8, onde podemos inclusive converter de forma automática interfaces VCL tradicionais para o Metropolis. Também foi evoluído o recurso de LiveBindings, criando uma forma gráfica para fazer a ligação entre componentes de tela e os dados.

Na versão XE4 do Delphi temos o suporte ao desenvolvimento de aplicativos para dispositivos móveis para iOS e no XE5 para Android. Já na versão XE6 temos apenas a melhoria nos recursos existentes e uma remodelagem da interface gráfica do IDE.

Porque estudar os conceitos de uma Linguagem de Programação

É normal que os estudantes se perguntem: por que estudar os conceitos de linguagens de programação? Essa é uma pergunta normal, pois existem vários estudos que se pode fazer de uma linguagem, sua sintaxe, suas bibliotecas nativas, frameworks e plug-ins extras. Mas existe uma série de benefícios que podem ser conseguidos ao estudar os conceitos de uma linguagem de programação, sendo alguns deles os seguintes:

  • O aumento da capacidade de codificação de sistemas: conhecer uma variedade maior de recursos de uma linguagem de programação nos possibilita o desenvolvimento de uma gama muito maior de algoritmos e nos permite explorar o que a linguagem tem de melhor para cada escopo de programa. Pode-se abrir a mente para novas formas de implementação de um mesmo problema, trazendo benefícios como um código mais simples e preciso, com um melhor desempenho. O estudo dos conceitos de uma linguagem de programação mostra aos desenvolvedores recursos preciosos que eles poderiam estar desconsiderando até o momento.
  • Maior entendimento para escolha da linguagem de programação correta para um problema: muitos desenvolvedores não tiveram uma base sólida conceitual de todos os tipos de linguagens de programação, e muitos aprenderam sozinhos a programar, muitas vezes sem passar por uma instituição de ensino.

Treinamentos e cursos específicos de determinada linguagem de programação vão diretamente à sintaxe da linguagem sem oferecer um embasamento teórico que indique que aquela linguagem é mais adequada para determinados tipos de problemas.

O fato é que as linguagens de programação não são boas para todos os tipos de projetos de software, sempre existem tipos de projetos onde são mais fracas ou mais fortes.

Quando estudamos seus conceitos, conseguimos analisar onde devemos aplicar determinada linguagem e quais os projetos deveríamos considerar a adoção de outra linguagem a fim de facilitar o desenvolvimento e manutenção dos sistemas.

  • Capacidade para aprender novas linguagens: ao aprendermos todos os conceitos relacionados a uma linguagem de programação fica muito mais fácil aprender outras linguagens. O mais importante não é aprender as sintaxes de uma linguagem e sim os conceitos relacionados àquela implementação.

Considerando um exemplo prático, em sistemas que adotam o paradigma orientado a objetos, temos o mecanismo de herança de classes, neste caso é muito mais importante sabermos como aplicar corretamente a herança na modelagem de um sistema do que a sintaxe específica de determinada linguagem.

Quem desenvolve em mais de uma linguagem de programação sabe que é bastante natural a passagem de uma sintaxe para outra, desde que a mesma possua o mesmo paradigma, por exemplo, Delphi e C#.

  • Aprender a importância de uma boa codificação: ao conseguir ter uma visão do porquê de determinada linguagem ter sido projetada daquela forma, levando os desenvolvedores a criarem códigos mais inteligentes e claros, de forma que outros desenvolvedores entendam rapidamente qual o objetivo das partes do sistema.

Determinados tipos de erros que ocorrem nos sistemas somente são identificados por desenvolvedores mais experientes que conseguem ver além daquela implementação.

  • Capacidade de implementar melhores linguagens: é óbvio que muito dificilmente nós desenvolvedores viremos a implementar novas linguagens de programação, mas estudá-las nos possibilita achar os pontos fortes e fracos de determinadas linguagens, de maneira que se fôssemos projetar uma nova linguagem, iríamos procurar aproveitar todos os pontos positivos de uma linguagem e retirar suas falhas, procurando a solução em outras tecnologias.
  • O avanço das linguagens de programação: entender o porquê daquela linguagem ter se tornado popular e quais as áreas que elas fazem maior sucesso, fazendo com que sejam aproveitadas nos projetos adequados e dando lugar a outras linguagens melhores nos projetos que não tenham efetividade.

Critérios de Avaliação de Linguagens de Programação

Existem diversos critérios que podem ser adotados a fim de fazer uma avaliação de uma linguagem de programação, dificilmente os cientistas da computação entram em consenso sobre quais são os critérios mais adequados para fazer avaliações da sintaxe das linguagens, porém alguns itens básicos são praticamente um consenso entre quase todos. Estes são os apresentados a seguir, na Tabela 1 que mostra em quais critérios as características de uma linguagem se enquadra.

Critérios
Característica Legibilidade Facilidade de Escrita Confiabilidade
Simplicidade X X X
Ortogonalidade X X X
Instruções de Controle X X X
Tipos de dados X X X
Projeto da Sintaxe X X X
Suporta a abstração X X
Expressividade X X
Verificação de tipos X
Tratamento de exceções X
Ponteiros Restritos X
Tabela 1. Critérios de avaliação

Legibilidade

Sem dúvida um dos critérios de avaliação de linguagens de programação mais importantes é o da legibilidade, que é o grau de facilidade com que os algoritmos criados naquela linguagem podem ser lidos e entendidos.

A facilidade de manutenção de aplicações está diretamente ligada à legibilidade do código, por isto essa se torna um dos critérios mais importantes de avaliação. A legibilidade de um programa também está ligada ao domínio do problema em questão, pois quando determinada linguagem de programação não foi projetada para determinado tipo de problema, é bastante provável que seu código fique confuso, tornando difícil de ser lido e interpretado. Por exemplo, se quisermos utilizar o Delphi para criarmos aplicações web de grande porte, sabemos que teremos dificuldade, pois o Delphi na sua essência não foi desenvolvido para atender esse nicho de mercado. Agora se quisermos criar aplicações Desktop complexas e com diversos formulários interagindo entre sim, provavelmente teremos uma aplicação simples e clara, pois é onde o Delphi se destaca desde o seu surgimento.

Simplicidade

A simplicidade de uma linguagem de programação está diretamente ligada a sua legibilidade, isto porque uma linguagem com uma sintaxe extensa é muito mais difícil de ser aprendida do que uma linguagem que possua poucos artefatos básicos. A maioria dos desenvolvedores geralmente aprende apenas parte de uma linguagem de programação, nunca ela no seu todo, ignorando alguns recursos. Este tipo de atitude é tomada principalmente para que não seja necessário um estudo mais profundo da linguagem, tornando o início do desenvolvimento rápido, trazendo resultados também rápidos. O problema desta abordagem é que outros desenvolvedores podem ter aprendido outra parte da linguagem, diferente daquela que aprendeu o desenvolvedor do sistema, tornando difícil a compreensão do código posteriormente.

Um exemplo no mundo Delphi deste problema pode ser visto quando temos alguns desenvolvedores que só sabem trabalhar de maneira procedural, com a adição de componentes e codificação de eventos. Outros desenvolvedores podem ter aprendido trabalhar de forma orientada a objetos, com a instanciação de classes e o seguimento de boas práticas de programação, como princípios SOLID e padrões de projeto. Um segundo ponto que realmente complica em termos de simplicidade de uma linguagem de programação é o fato de ela ter diversas maneiras de realizar uma única tarefa. Por exemplo, em C para incrementarmos uma variável numérica simples existem diversas maneiras, conforme pode ser visto na Listagem 1.

  1. contador = contador + 1
  2. contador += 1
  3. contador++
  4. ++contador
Listagem 1. Incrementando uma variável simples em C

Veja que apesar de em determinadas situações esses operadores terem significados diferentes, quando são aplicados a variáveis simples individualmente eles têm o mesmo propósito, incrementar em um a variável.

Neste ponto o Delphi traz mais simplicidade em relação a outras linguagens, pois existe uma única forma nativa do compilador para incrementar em um uma variável, como mostrado a seguir:

var contador: integer;
contador := contador + 1;
Nota: Muitos podem estar pensando que existe sim outra maneira de incrementarmos em um uma variável numérica em Delphi, através do procedure Inc, porém devemos observar que o Inc não é um recurso nativo disponibilizado pelo compilador e sim um procedimento implementado na unit System, o que são coisas totalmente diferentes.

Outra característica que prejudica a simplicidade de uma linguagem de programação é a possibilidade de fazermos sobrecarga de operadores na qual um único símbolo pode ter mais de um significado. Embora seja um recurso útil, pode levar ao desenvolvimento de códigos complexos, principalmente se não for adotado com cautela por parte do criador da sobrecarga. Um exemplo simples de sobrecarga é a do símbolo de soma (+), onde ele pode tanto somar inteiros ou concatenar strings. Nestes casos é bastante indicado o uso de sobrecarga de operadores, pois torna a linguagem mais simples e enxuta.

Nota: O recurso de sobrecarga de operadores é suportado no Delphi desde a versão 2005 (somente para .NET) e a partir de 2006 para Win32. Este recurso foi adicionado na época pela Borland, principalmente para manter a compatibilidade com a plataforma .NET.

Ortogonalidade

A ortogonalidade numa linguagem de programação significa a quantidade pequena de instruções primitivas combinado com um número pequeno de maneiras para construir estruturas de controle e laços de repetição. Na prática, significa o número de regras que determinada linguagem possui. Linguagens com baixa ortogonalidade possuem muitas exceções às regras da linguagem, já linguagens com alta ortogonalidade, como o Delphi possuem poucas exceções às regras básicas. Como exemplo de regras, podemos definir o bloco begin/end exigido pelo Delphi nas estruturas de controles, rotinas e laços de repetição. Esta é uma regra única de bloco, sendo a única exceção à regra o laço de repetição Repeat, onde não somos obrigados a informar o begin/end, saindo um pouco da regra geral da linguagem.

A ortogonalidade também está diretamente ligada com a simplicidade, quanto mais ortogonal é a linguagem de programação, menos exceções existirão quanto às regras da linguagem. Menos exceções levam a uma codificação mais regular, tornando a linguagem mais fácil de ser lida, entendida e aprendida. Outro exemplo de exceção à regra existente na Delphi Language é o fato de que todas as instruções obrigatoriamente devem ser finalizadas com ponto e vírgula (;), com a exceção de quando esta instrução estiver dentro de um comando condicional como o IF e for um comando único, conforme pode ser visto na Listagem 2.

if A <> B then
Writeln(‘A é diferente de B’)
Listagem 2. Exceção à regra geral no Delphi

Instruções de Controle

Até o final da década de 60 existiam linguagens de programação que tinham muito pouca legibilidade, principalmente em relação às instruções de controle, onde o recurso utilizado era o famoso GOTO para conseguirmos mudar o fluxo de execução de um algoritmo. No início da década de 70, devido à falta de legibilidade destas linguagens, surgiram iniciativas para resolver estes problemas. Foi aí que surgiram as linguagens de programação estruturadas, principalmente pela falta de legibilidade que o comando Goto causava nos programas da época.

Uma linguagem de programação Top-Down, ou seja, que pode ser lida de cima para baixo, é muito mais fácil de ser entendida do que termos que pular de uma instrução para outra de forma indiscriminada. A maioria das linguagens de programação projetadas a partir do início da década de 70, devido suas boas estruturas de controle, praticamente eliminou a necessidade de utilização do comando Goto. Apesar de geralmente ele ainda estar disponível na maior parte das linguagens de programação, ele é muito pouco utilizado.

Falando especificamente de Delphi, a maioria dos desenvolvedores nem sabe da existência e funcionamento do comando Goto, mas ele existe na Delphi Language. Na Listagem 3 podemos visualizar um exemplo simples do funcionamento.

  1.  program ExemploGoto;
  2.  {$APPTYPE CONSOLE}
  3.  uses
  4.    System.SysUtils;
  5.  var
  6.    Ind: Integer;
  7.  label
  8.    GotoLabel;
  9.  begin
  10.   for Ind := 1 to 5 do
  11.   begin
  12.     Writeln('Ind = ' + IntToStr(Ind));
  13.     if Ind = 3 then
  14.       Goto GotoLabel;
  15.   end;
  16.   Writeln('Final do Loop');
  17.   GotoLabel:
  18.     Writeln('Final do Loop em ' + IntToStr(Ind));
  19.   Readln;
  20. end.
Listagem 3. Utilização do Goto em Delphi

No exemplo temos a definição de um Goto nas linhas 7 e 8, já na linha 14 estamos indicando que queremos saltar para a instrução GotoLabel na linha 17, fazendo com que seja interrompido o laço de repetição.

Tipos de Dados

Um sistema de informações produz resultados através da manipulação de dados. Um item determinante para indicar a facilidade com que eles poderão efetuar tal tarefa diz respeito aos tipos de dados oferecidos pela linguagem utilizada se encaixarem com o domínio do problema real. Por este motivo é muito importante uma linguagem possuir uma gama muito boa de tipos de dados e estruturas.

Os tipos de dados básicos mais comuns da linguagem e que não são criados com base em outros são chamados de tipos primitivos. O fato de uma linguagem de programação fornecer tipos de dados primitivos adequados para variáveis é outra característica que traz bastante legibilidade.

Por exemplo, existem linguagens como C que não possuem o tipo de dado Booleano, sendo necessário os desenvolvedores utilizarem outros tipos de dados. Em linguagens com essa característica geralmente define-se zero para false e um para verdadeiro. Ao nos depararmos com instruções como estas no meio do código, não temos a clareza do que realmente ela representa dentro da aplicação, sendo necessário uma análise da documentação do código para termos a convicção de que ela representa uma indicação de verdade. Além dos tipos de dados primitivos comuns existem outros dois tipos de dados não escalares que são os vetores e os registros.

Projeto da Sintaxe

A sintaxe de uma linguagem de programação tem influência direta na legibilidade de uma aplicação. Existem algumas escolhas na hora de se projetar a linguagem que pode aumentar ou diminuir a legibilidade dos programas:

  • Formato dos identificadores: se determinada linguagem restringe a um número muito pequeno de caracteres os identificadores, acaba trazendo uma baixa legibilidade. Algumas linguagens limitam muito o tamanho dos identificadores, de forma que não conseguimos representar de forma adequada principalmente o nome das variáveis.

No caso do Delphi, felizmente não temos este tipo de problema, já que podemos ter um número ilimitado de caracteres para representar os identificadores (nomes de variáveis, constantes, funções, etc.).

  • Palavras reservadas: a legibilidade de um programa também está altamente atrelada pela forma como estão definidas as palavras reservadas, principalmente as que se referem ao início e fim de um bloco condicional ou iterativo. Algumas linguagens como o Delphi usam um par casado de instruções que indicam o início e fim de um bloco.

Isso prejudica a legibilidade dos códigos, pois os blocos de códigos terminam sempre da mesma maneira, tornando difícil às vezes determinar qual o grupo de instruções está sendo finalizado em determinado momento (Listagem 4).

Algumas linguagens resolvem este problema criando uma sintaxe distinta para cada tipo de bloco, usando, por exemplo, end if e end loop para diferenciar os blocos de código. Outra característica das palavras reservadas é a de se a linguagem de programação permite ou não usá-las para nome de variáveis nos programas.

Se permite, pode trazer uma grande confusão, pois muitas vezes não saberíamos se determinada instrução se refere a uma instrução nativa do compilador ou o nome de uma variável.

O Delphi neste quesito não deixa a desejar, já que somos impedidos de criar nomes de variáveis com palavras reservadas, ocorrendo erro em tempo de compilação se assim o fizermos.

  • Significado das instruções: linguagens de programação devem projetar sua sintaxe de modo que as instruções representem fielmente o que significam e que suas instruções não tenham mais de um significado dentro da construção de um programa. O Delphi neste ponto é uma linguagem bastante clara quanto a sua sintaxe, onde cada instrução representa exatamente seu propósito (if, case, function).

Um dos únicos itens em que o Delphi falha neste quesito é no uso da palavra Interface. Ela pode tanto representar a criação de uma Interface na orientação a objetos, quanto pode representar um bloco de interface de declarações de classes e métodos dentro de uma unit, conforme pode ser visto na Listagem 5 (linhas 2 e 4).

  1.  procedure Teste;
  2.  begin
  3.    while True do
  4.    begin
  5.      if True then
  6.      begin
  7.        //código
  8.      end;
  9.    end;
  10. end;
Listagem 4. Falta de legibilidade no final de blocos
  1. unit Pessoa;
  2. interface
  3. type
  4.   IPessoa = interface
  5.     procedure Teste;
  6.   end;
  7. implementation
  8. end.
Listagem 5. Mesma instrução representando duas funções diferentes
Nota: Alguns plug-ins como o CnPack oferecem um mecanismo de melhoria no entendimento de blocos begin/end aninhados, fazendo uso de cores diferentes para cada tipo de estrutura de controle, aumentando a legibilidade dos códigos e facilitando o entendimento da sintaxe. Na seção Links está disponível o endereço para download dessa ferramenta.

Facilidade de Escrita

A facilidade de escrita representa o quão fácil é o desenvolvimento de um programa para um determinado domínio. Isso significa que determinada linguagem de programação pode ter uma facilidade de escrita para um determinado tipo de problema e outras não.

É o típico caso onde dizemos que não existe uma linguagem melhor ou pior, tudo depende do tipo de sistema que deseja se deseja desenvolver, cabendo ao desenvolvedor analisar qual é a linguagem mais adequada para cada situação.

Não se pode comparar a facilidade de escrita de duas linguagens de programação escolhendo um domínio específico. Por exemplo, é muito mais fácil criar uma aplicação baseada em interfaces gráficas para Windows Desktop utilizando Delphi do que utilizando a linguagem C e isso não significa que o Delphi seja uma linguagem muito mais fácil de escrita, é que o Delphi foi criado para este fim. O mesmo se pode falar de aplicativos de sistema de baixo nível, usando C a tarefa é bem mais simples de que se fossemos utilizar o Delphi, pois o C foi projetado para atender este fim.

Suporte a Abstração

A abstração é um item fundamental nos atuais projetos de linguagens de programação, pois ela possibilita definirmos estruturas e operações complexas de modo a permitir que muitos dos detalhes sejam ignorados. O nível de abstração permitido por uma linguagem e a naturalidade como ela é descrita tem um grande impacto na facilidade de escrita. Podemos ter dois tipos de abstrações: processos e dados.

Como exemplo de abstração de processos podemos citar a possibilidade de criarmos classes e métodos para realizarmos a tarefa de exportar determinado conjunto de informações para o Excel. Se não tivéssemos suporte a abstração, esta tarefa teria de ser replicada todas as vezes que fosse necessário realizar esta tarefa, tornando o código mais poluído.

Quanto à abstração de dados, podemos usar como exemplo uma lista de informações de um aluno, como nome, idade e curso. Se utilizássemos uma linguagem que não suporta abstração de dados teríamos que criar três vetores e sincronizá-los de forma que cada posição dos vetores representasse a informação referente àquele aluno. No Delphi temos a possibilidade fazer abstração destes dados utilizando uma estrutura (records) ou uma classe para isso, conforme Listagem 6.

  1.  Alunos = record
  2.    Nome: string;
  3.    Idade: Integer;
  4.    Curso: string;
  5.  end;
  6. 
  7.  TAluno = class
  8.  strict private
  9.    FNome: string;
  10.   FIdade: Integer;
  11.   FCurso: string;
  12. public
  13.   property Nome: string read FNome write FNome;
  14.   property Idade: Integer read FIdade write FIdade;
  15.   property Curso: string read FCurso write FCurso;
  16. end;
Listagem 6. Abstração de dados em Delphi

Expressividade

A expressividade de uma linguagem de programação representa as instruções que sua sintaxe permite de forma a tornar a codificação mais simples e enxuta. Isso se consegue com a adição de operadores que tornam a codificação mais elegante e menos verbosa, simplificando a codificação.

Em algumas linguagens de programação temos a opção de fazer o auto incremento utilizando a instrução cont++, enquanto em outras como o Delphi necessitamos de uma instrução maior (cont := cont + 1), o que torna a linguagem menos expressiva.

Outro recurso das linguagens de programação modernas é o for, que também torna as linguagens mais expressivas, devido ao fato de simplificar bastante a tarefa de criarmos laço de repetição que antes só era permitido através de comandos while.

Confiabilidade

A confiabilidade de um programa se refere à possibilidade da linguagem de programação oferecer alguns recursos que os desenvolvedores possam utilizar, de forma a evitar erros inesperados e bugs nos aplicativos.

Os itens de confiabilidade analisados no artigo serão o da verificação de tipos, tratamento de exceções e restrição de ponteiros na linguagem.

Verificação de Tipos

A verificação de tipos é um recurso existente para garantir que os operandos de um operador sejam de tipos compatíveis. Tipos compatíveis são aqueles que são válidos para o operador, já tipos incompatíveis se referem à aplicação de um operador a um operando de tipo impróprio.

A verificação de tipos é um item muito importante em relação à confiabilidade de uma linguagem de programação. Ela consiste na execução de testes de validação por parte do compilador para detectar erros de atribuição às variáveis.

É muito melhor e mais produtivo quando temos a detecção de erros de atribuição em tempo de compilação do que em tempo de execução, isto porque torna mais rápida a correção e evita que códigos que não tenham sido testados adequadamente acabem indo para ambientes de produção com erros que serão somente detectados posteriormente pelo usuário.

Linguagens que possuem verificação de tipos de forma dinâmica, como o JavaScript, permitem somente a validação dos tipos em tempo de execução. Esta forma de validação por um lado traz maior flexibilidade de desenvolvimento para o programador, mas por outro lado traz uma menos segurança quanto à precisão dos dados.

Nos dias de hoje as linguagens fortemente tipadas possuem uma admiração muito grande por parte dos desenvolvedores de software. Linguagens fortemente tipadas têm seus tipos definidos de forma estática, ou seja, uma determinada variável possui um único tipo fixo especificado antes da compilação.

O Delphi neste sentido atende a este quesito de segurança, pois a verificação de tipos é feita durante a compilação dos programas desenvolvidos. A exceção fica por parte do tipo Variant, onde é permitido fazer a atribuição de qualquer valor para variáveis deste tipo.

Tratamento de Exceções

Grande parte dos hardwares são capazes de detectar erros em tempo de execução, como o estouro de um tipo inteiro. Em linguagens que não são capazes de detectar erro, o que ocorre simplesmente é o encerramento do programa abruptamente e o controle passa para o sistema operacional.

A reação do sistema operacional quando ocorre um erro inesperado e o programa se fecha é a de exibir uma mensagem de erro diagnosticando o problema ocorrido. Tal informação pode ser muito útil ou não fazer nenhum sentido para o usuário do programa. O recurso de tratamento de exceções é a habilidade que uma linguagem de programação tem de interceptar erros em tempo de execução e tratá-los, continuando com o programa sem que o mesmo precise ser reiniciado.

O tratamento de exceções é um recurso indispensável em qualquer linguagem de programação e o Delphi possibilita este tratamento de modo simples, conforme Listagem 7.

  1.   try
  2.     try
  3.       Resultado := Num1 / Num2;
  4.     except
  5.       raise;
  6.     end;
  7.   except
  8.     on E: Exception do
  9.       Writeln(E.ClassName, ': ', E.Message);
  10.  end;
Listagem 7. Tratamento de Exceções Delphi

Apenas para esclarecimento, na linha 5 temos a instrução Raise, que tem a função de propagar a exceção para o bloco externo, ou seja, ela informa ao compilador que não será ali feito o tratamento de exceção e sim no bloco try/except externo.

Existe um segundo bloco de tratamento de exceção chamado try/finally, que foi criado para a liberação segura de recursos. Todo o código que estiver contido dentro do bloco finally será executado, independente do que ocorrer no interior do bloco try. Na Listagem 8 temos um exemplo de utilização.

  1.  program Exemplo;
  2.  {$APPTYPE CONSOLE}
  3.  uses
  4.    System.SysUtils, System.Classes;
  5.  var
  6.    Texto: TStringList;
  7.  begin
  8.   Texto := TStringList.Create;
  9.   try
  10.     Texto.Add('João');
  11.     Texto.Add('Batista');
  12.     Writeln(Texto.Text);
  13.   finally
  14.     Texto.Free;
  15.   end;
  16.   readln;
  17. end.
Listagem 8. Uso do Try/Finally no Delphi

No exemplo mostrado temos a liberação do objeto Texto no bloco finally, para que independente do que ocorrer no bloco try, no caso a adição de informações, o objeto seja liberado da memória, evitando a ocorrência de vazamento de memória.

Ponteiros Restritos

Ponteiros são tipos de dados que se referem diretamente a um outro valor alocado em outra posição de memória através de seu endereço. Nos dias atuais a utilização de ponteiros principalmente em linguagens de programação de alto nível é muito rara. Algumas linguagens como o Java nem suportam mais este recurso.

O fato de não suportar o uso de ponteiros, segundo alguns cientistas da computação, torna a linguagem mais segura e confiável.

No Delphi utilizamos o operador ^ (circunflexo) para declarar uma variável do tipo ponteiro. Usamos também o operador @ precedendo variáveis “normais” para obter o endereço delas. O inverso de @ seria usar ^ depois de uma variável-ponteiro, para que possamos acessar o seu valor. Um ponteiro recém declarado que não aponta para nenhum lugar tem o valor nil.

Na Listagem 9 temos um exemplo simples de emprego de ponteiros na Delphi Language.

  1.  program Exemplo;
  2.  {$APPTYPE CONSOLE}
  3.  uses
  4.    System.SysUtils;
  5.  var
  6.    Var1: Integer;
  7.    Var2: Integer;
  8.    Ponteiro: ^Integer;
  9.  begin
  10.   Var1 := 123;
  11.   Var2 := 456;
  12.   Writeln('Endereço Var1 = ' + IntToStr(Integer(@Var1)));
  13.   Writeln('Valor de Var1 = ' + IntToStr(Var1));
  14.   Ponteiro := @Var1;
  15.   Writeln('Endereco Ponteiro = ' + IntToStr(Integer(Ponteiro)));
  16.   Writeln('Valor do Ponteiro = ' + IntToStr(Integer(Ponteiro^)));
  17.   readln;
  18. end.
Listagem 9. Uso de ponteiros no Delphi

Como os ponteiros têm a capacidade de acessar variáveis que não são explicitamente declaradas para ele, há uma possibilidade maior de erros de codificação. Apesar disso, o poder oferecido pelos ponteiros é tão grande que em determinadas tarefas, principalmente aquelas referentes ao desenvolvimento de sistemas básicos, o uso de ponteiros pode se mostrar bastante útil.

Custo da Linguagem

O custo de uma linguagem de programação se refere a muitos pontos que serão elencados nos próximos parágrafos.

O primeiro ponto a ser analisado é o custo que terá o treinamento de desenvolvedores para a linguagem escolhida, que depende muito da simplicidade e da ortogonalidade da sintaxe, além, é claro, do nível atual dos desenvolvedores que serão treinados. Linguagens mais poderosas e com maiores recursos despendem maior investimento de dinheiro e tempo para aprendê-las.

Em segundo lugar temos o custo de desenvolver aplicações para esta linguagem, o que depende da facilidade de escrita, a qual também depende do escopo do problema que deve ser solucionado. Os esforços empregados no desenvolvimento de linguagens de programação de alto nível e IDEs robustos foram feitos para que fosse diminuído o custo de desenvolvimento de softwares.

Tanto o custo de treinar desenvolvedores quanto os de escrever programas na linguagem podem ser minimizados na utilização de um bom ambiente de desenvolvimento, que possibilite a automatização de tarefas básicas e ofereça recursos de facilidades na escrita de código.

O terceiro custo a ser analisado é o de compilar aplicações na linguagem. No passado compiladores demoravam bastante na tarefa de fazer a conversão do código da linguagem no código de máquina que seria executado no hardware. Hoje, felizmente possuímos compiladores rápidos, principalmente também pelo avanço do nível de capacidade dos hardwares.

O quarto ponto é o custo de executar programas escritos em uma linguagem, que está diretamente associado ao projeto dela. Uma linguagem que faz muitas verificações de tipos em tempo de execução, por exemplo, não será rápida, mesmo que o compilador seja muito bom. Hoje em dia o tempo de execução de um aplicativo já não é prioridade no projeto de linguagens, principalmente com os avanços a nível de hardware.

No passado, devido principalmente ao baixo nível de memória, os programas deviam ser cuidadosamente escritos e em um nível mais baixo para obter o melhor dos recursos existentes das máquinas limitadas. Geralmente há de se fazer uma escolha entre o custo de compilação de um programa e a velocidade de execução do mesmo. Existe uma fase da compilação chamada otimização, que é uma técnica utilizada pelos compiladores para diminuir o tamanho e aumentar a velocidade da execução de um determinado programa.

Se pouca otimização for feita, a compilação é bem mais rápida, porém a execução do programa se torna mais lenta. Porém, se for despendido bastante tempo para otimização, a compilação será mais demorada, mas teremos um programa executável mais rápido.

O quinto item a ser considerado diz respeito ao custo de utilização da linguagem e/ou IDE de desenvolvimento. Uma linguagem cujas ferramentas de desenvolvimento são caras ou criadas apenas para poucos tipos de hardware terão menores chances de se tornarem populares no mundo do desenvolvimento.

O sexto fator se refere ao custo de uma confiabilidade baixa. Se um sistema crítico falha, como o de controle de voos, por exemplo, o custo de adoção desta linguagem pode se mostra muito alto. Linguagens que possuem um histórico de casos de usos onde houve sérios problemas nos seus sistemas tendem a cair em desuso.

O último fator a ser considerado em relação ao custo é o quando o sistema desenvolvido em determinada linguagem irá depender de manutenções, inclusão de funcionalidades e correção de erros. O custo de manutenção de uma linguagem de programação está diretamente ligado à legibilidade da mesma e de um bom desenvolvimento por parte do desenvolvedor.

A facilidade de manutenção é um fator crucial nos dias atuais, pois se calcula que atualmente o custo de manutenção supera em até em quatro vezes o custo do desenvolvimento inicial do sistema.

De todos os fatores que influenciam no custo de desenvolver em determinada linguagem de programação, os mais importantes são: facilidade de desenvolvimento de programas, facilidade na manutenção e confiabilidade no resultado.

Existem muitos outros critérios que podem ser levados em consideração na avaliação do custo, como a portabilidade, que é a capacidade de uma implementação ser movida para outro hardware ou sistema operacional, mas não são fatores tão decisivos como os descritos acima.

A linguagem Delphi possui uma sintaxe poderosa, com recursos avançados, como o uso de estruturas e ponteiros. O IDE foi evoluindo com o passar dos anos e nas últimas versões passou a possibilitar o que existe de mais promissor no mercado, a possibilidade de desenvolvimento de aplicativos para dispositivos móveis e com certeza irá impulsionar a ferramenta e ter maior visibilidade entre os desenvolvedores, aumentando a sua popularidade.


Saiu na DevMedia!

  • Buscas semânticas com Elasticsearch:
    Elasticsearch é uma ferramenta de busca de alta performance. Com ela podemos armazenar grandes volumes de dados, analisá-los e processá-los, obtendo resultados em tempo real.

Saiba mais sobre Delphi ;)