Tipagem de dados

Quando estudamos variáveis, aprendemos que elas possuem tipos. Há, entretanto, outro aspecto que precisamos observar com relação à tipagem de dados em linguagens de programação: a maneira como cada linguagem lida com os tipos de dados das variáveis.

🏡 Vinculação de tipos

Uma linguagem de programação pode optar por lidar com tipagem de forma estática ou dinâmica. A seguir, acompanharemos uma explicação sobre cada abordagem.

Estática

Quando uma linguagem adota a abordagem de tipagem estática, isso significa que uma variável armazenará apenas valores do tipo informado em sua declaração.

Uma variável int c, por exemplo, só aceitará valores inteiros durante todo o seu ciclo de vida. É o que acontece na linguagem de programação C, que estamos usando nessa disciplina. Vejamos um exemplo:

#include<stdio.h>
#include<stdlib.h>

int main(void){
    int x = 10;
    x = 5.7;
    printf("Valor de X: %d", x);
    return 0;
}

A saída desse programa será o número 5, mesmo que tenhamos atribuído o valor 5.7 para a variável x. Isso acontece porque a vinculação acontece antes do tempo de execução do programa.

Embora pareça limitante, essa abordagem contribui para a redução de eventuais defeitos de implementação.

Dinâmica

Em contraponto à abordagem anterior, a vinculação dinâmica de tipo acontece pela primeira vez já em tempo de execução. Em linguagens que adotam essa estratégia (como PHP, JavaScript e Python), uma variável pode armazenar diferentes tipos de dado durante o seu ciclo de vida. Vejamos o exemplo a seguir, na linguagem JavaScript:

let variavel = 5;
console.log("Tipo da variável: " + typeof variavel);
variavel = "Jose";
console.log("Tipo da variável: " + typeof variavel);
console.log("Valor da variável: " + variavel);

Nesse caso, a variável variavel iniciará com o tipo number, sendo alterada posteriormente para o tipo string.

🧠 Pensando criticamente

Por um lado, a vinculação dinãmica traz mais flexibilidade para os desenvolvedores. Se você estiver desenvolvendo um programa que pode lidar com diferentes tipos de dados, como string e int, a tipagem dinâmica é suficiente para tratar ambos os casos.

Por outro lado, há duas principais desvantagens decorrentes do uso dessa estratégia:

  1. Menor confiabilidade: uma vez que os processos ocorrem em tempo de execução, a detecção de erros do compilador não é tão eficaz como nas linguagens com vinculação estática.
  2. Custo computacional: nessa estratégia, o custo computacional é superior pois torna-se necessário efetuar a verificação de tipos em tempo de execução. Além disso, deve existir um descritor para cada variável, com o intuito de armazenar o tipo atual. Finalmente, o espaço de memória ocupado pode variar, já que cada tipo de dado ocupa um espaço diferente de armazenamento.
Na linguagem de programação Ruby, por exemplo, não existe o conceito de tipo de dado. Assim, não há verificação de tipos.

Ainda conforme Sebesta (2018), é comum que as linguagens que usam vinculação dinâmica adotem intepretadores em detrimento de compiladores. O motivo para isso é simples: as instruções dos computadores pressupõem que os tipos dos operandos já são conhecidos. Desse modo, um compilador não pode elaborar uma instrução de máquina A + B sem que os tipos de A e de B sejam conhecidos em tempo de compilação.

Em contraponto, as linguagens com vinculação estática de tipos raramente são puramente interpretadas, já que a tradução para a linguagem de máquina pode ser facilmente realizada de forma mais eficiente. Tipicamente, uma linguagem puramente interpretada leva até 10 vezes mais tempo para executar um código de máquina equivalente.

💪 Verificação de tipos

Além da estratégia de vinculação de tipos, as linguagens de programação também podem variar conforme a verificação dos tipos das variáveis. De acordo com Sebesta (2018), essa atividade visa a garantir que os operadorandos de um operador são de tipos compatíveis.

Para pensar: qual seria o resultado da seguinte operação?
variavel1 = "Nome"
variavel2 = 7
variavel3 = variavel1 + variavel2

Nome7? Operação inválida? A resposta vai depender da linguagem de programação utilizada. Agora, entenderemos o porquê.

Tipos de dados são compatíveis quando as regras da linguagem possibilitam sua conversão implicita

Tipagem forte

Uma linguagem de programação é classificada como fortemente tipada quando é capaz de identificar todos os erros de tipo. Para isso, os tipos de todos os operandos devem ser determinados em tempo de execução ou de compilação.

A principal vantagem do uso desse tipo de linguagem está na identificação de usos incorretos de variáveis que podem gerar erros de tipo. Nessas linguagens, quando desejar executar operações com diferentes tipos de dados, o programador deve fazer a conversão de tipos (chamada de casting, em inglês).

Vejamos o exemplo em Python:

x = "AED"
y = 1
r = x + y
print(r)

A saída desse programa será:

ERROR!
Traceback (most recent call last):
  File "<string>", line 3, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'
>

Como podemos observar na mensagem de saída, houve um erro de incompabilidade de tipos. Para executar essa operação, o código deve ser alterado para prever a conversão da variável y do tipo int para string:

x = "AED"
y = 1
r = x + str(y)
print(r)

A saída agora será:

AED 1

Com relação à linguagem C, existe uma discussão sobre sua classificação. Alguns autores, como Sebesta (2018), entendem que a linguagem não é fortemente tipada por oferecer o recurso Union, mas isso é assunto para discutirmos em AED II.

Tipagem fraca

Nas linguagens consideradas fracamente tipadas, existe maior flexibilidade quanto à verificação do tipo. Nesses casos, a própria linguagem se encarrega de fazer conversões de tipo. Vejamos um exemplo na linguagem de programação JavaScript:

let var1 = 120
let var2 = "10"
let var3 = var1 * var2
console.log(var3)

A saída será

1200

Agora, vamos para o segundo exemplo:

let var1 = 1
let var2 = "1"
let var3 = var1 + var2
console.log("Conta 1: " + var3)

let var4 = var1 - var2
console.log("Conta 2: " + var4)

A saída será

Conta 1: 11
Conta 2: 0

Opa, agora a situação ficou esquisita, não é?

Isso acontece porque a linguagem adotou diferentes estratégias de conversão de tipos. No primeiro caso, houve a conversão de var1 para o tipo string (a concatenação das duas strings resulta em 11).

No segundo caso, a variável var2 foi convertida para o tipo number. Logo, 1 - 1 = 0.

Se ganhamos maior flexibilidade de um lado, ganhamos também maior responsabilidade no desenvolvimento das soluções computacionais.

🎬 Vídeos de apoio

Para apoiar o seu processo de aprendizado, recomendo que você assista ao vídeo a seguir, do canal Código Fonte TV. Observe que, durante o vídeo, os apresentadores mostram códigos produzidos em diversas linguagens de programação para exemplificar como cada linguagem pode adotar abordagens distintas.

🗪 Por que estudar tipagem?

Nas disciplinas introdutórias de programação, é frequente o uso da linguagem de programação C, que adota a tipagem estática. Assim, esse assunto pode não ser uma grande preocupação para você neste momento, mas é importante conhecê-lo, já que você certamente trabalhará com linguagens diferentes num futuro próximo. Linguagens amplamente utilizadas pelo mercado, como JavaScript e Python, adotam tipagem dinâmica.

Conhecer como a linguagem de programação lida com tipos é de fundamental importância para evitar erros no projeto.

Em JavaScript, por exemplo, existe o TypeScript, que adiciona tipagem estática à linguagem.

Acompanhe um vídeo que discute essa perspectiva. Não se preocupe com detalhes e algumas informações que você provavelmente ainda não conhece.

📖 Bibliografia

Livros

  • SEBESTA, Robert W. Conceitos de linguagens de programação. 11. ed. Porto Alegre: Bookman, 2018. xvi, 757 p. ISBN 9788582604687.

Artigos