Linguagens de programação

As linguagens de programação podem ser discutidas sob diversos aspectos. O suporte a paradigmas de programação talvez seja um dos aspectos mais observados, mas há outras características a se discutir quando se deseja escolher uma linguagem de programação para desenvolver um sistema. Vamos às características:

Tipagem

Como já sabemos desde AED 1, as variáveis armazenam alguns tipos de dados. Entretanto, a maneira como as linguagens de programação lidam com esses tipos de dado podem variar.

Tipagem fraca

Em linguagens de tipagem fraca, o sistema de tipos é menos restritivo e permite conversões automáticas entre diferentes tipos de dados sem que o programador tenha que realizar conversões explícitas. Isso pode aumentar a flexibilidade e reduzir o código necessário para certas operações, mas também pode levar a erros sutis e difíceis de detectar. Por exemplo, em JavaScript (uma linguagem de tipagem fraca), é possível somar números e strings sem conversão explícita:

var resultado = "O total é " + 5 + 10; // "O total é 510"`

Neste exemplo, o JavaScript converte automaticamente os números em strings para realizar a concatenação, o que pode não ser o comportamento esperado pelo desenvolvedor.

Tipagem forte

Linguagens de tipagem forte, por outro lado, são mais rigorosas em suas regras de tipo. Elas geralmente requerem que o programador faça conversões explícitas entre tipos incompatíveis, o que ajuda a prevenir erros. Isso garante que o código é mais previsível e menos propenso a erros de tipo em tempo de execução.

Python é um exemplo de linguagem com tipagem forte:

numero = 5
texto = "O número é " + str(numero)  # Necessário converter explicitamente o número para string
print(texto)  # "O número é 5"

Em geral, C tem muitas características de uma linguagem com tipagem forte. Segundo Robert W. Sebesta (2011), no livro "Conceitos de Linguagens de Programação", o recurso de Union implica a não adequação da linguagem a essa categoria.

Inferência de tipos

Outro aspecto bastante importante com relação à tipos em linguagens de programação está na abordagem adotada pela linguagem para inferência de tipos. A inferência de tipos refere-se à capacidade de uma linguagem de programação de deduzir automaticamente o tipo de uma expressão no momento da compilação (em linguagens estáticas) ou durante a execução (em linguagens dinâmicas).

Estática

Na inferência de tipos estática, o tipo de cada variável e expressão é determinado em tempo de compilação e não pode mudar ao longo do tempo de execução. Linguagens como C, Java e Rust utilizam inferência de tipos estática.

int variavel; // variavel será int sempre

Isso proporciona uma série de vantagens, como melhor desempenho em tempo de execução, menor consumo de recursos, e mais segurança no código, uma vez que muitos erros podem ser captados durante a compilação.

Por exemplo, a linguagem Rust é conhecida por sua segurança de memória, que é em grande parte garantida durante a fase de compilação através da inferência de tipos.

Dinâmica

Por outro lado, a inferência de tipos dinâmica ocorre em tempo de execução. Linguagens como Python, JavaScript e Ruby são exemplos de linguagens que adotam essa abordagem. Veja um exemplo em Python:

variavel = "ufmt"
variavel = 10

A inferência de tipos dinâmica oferece maior flexibilidade e rapidez no desenvolvimento, pois permite aos desenvolvedores escrever código sem se preocupar explicitamente com a definição de tipos.

Isso pode facilitar a prototipagem rápida e a execução de mudanças em tempo real, mas também pode levar a erros em tempo de execução que seriam evitados com a inferência de tipos estática.

Por exemplo, em JavaScript, o tipo de uma variável pode mudar ao longo de sua vida útil no código, o que pode introduzir bugs se não for devidamente gerenciado.

Vejamos um exemplo:

function calcularTotal(a, b, c) {
    return a + b + c;
}

// Exemplo de uso esperado:
console.log(calcularTotal(10, 20, 30)); // Saída esperada: 60

// Chamada com tipos misturados, potencialmente por engano:
console.log(calcularTotal(10, "20", 30)); // Saída: "102030"

Neste caso, a função calcularTotal é chamada com um array que inclui uma string ("20"). Em JavaScript, o operador + é sobrecarregado para servir tanto para soma quanto para concatenação de strings.

Quando o interpretador encontra um número seguido de uma string durante a adição, ele converte todos os números subsequentes em strings e realiza a concatenação ao invés de uma soma numérica. Isso resulta na saída inesperada de "102030".