Atributos das Variáveis

O que mais além do valor e nome?

Praticamente onipresente independente da linguagem de programação e apesar de ter importância indiscutível, pouco se fala a respeito. Estou aqui para interromper essa injustificável escassez de textos sobre essa que habita no coração de todas as pessoas desenvolvedoras: as variáveis.

Geralmente, o conceito é grosseiramente definido como: negócio que tem um valor.

Vou me aprofundar um pouco mais porque, como sabemos, as variáveis merecem e são capazes de arruinar o dia e até semanas de qualquer um que tenha brincado com desenvolvimento de software. Falo isso com propriedade e, principalmente, vergonha. Mas não suficiente para deixar de confessar que passei alguns ANOS da minha vida achando que, para nomear uma variável, só era possível utilizar uma mísera letra.

Sim, você não leu errado. Quando eu era mais novo, todas minhas variáveis eram identificadas só com uma letra. Tipo x, y, z, a, b… Mas eu era jovem e os jovens são burros. O que ameniza minha situação.

Alegre-se em saber que é com um ex-jovem, mas não ex-buro, que você vai aprender algo hoje. A não ser que você seja jovem. Nesse caso, nem tente. Volte daqui alguns anos.

Para os desatentos, reforço: sim, as variáveis possuem atributos. Como citei há pouco, um deles é o nome, ou, se você quiser pagar de pedante, identificador.

Mas o nome não está nem perto de ser o único atributo de uma variável. Uma variável pode ser caracterizada como um conjunto de seis atributos:

Largamente amparado pelo livro Conceitos de Linguagens de Programação, falarei mais a respeito de cada um desses atributos.

Comecemos pelo começo, a definição formal de uma variável:

Uma região de memória previamente identificada cuja finalidade é armazenar os dados em um programa.

Para exemplificar este artigo, observe com atenção o trecho de Javascript (linguagem que permite mutação de variáveis) a seguir:

O trecho de código soma todos os valores inteiros de 1 até 10 e armazena o resultado na variável identificada como sum. Depois de somar tudo, o código exibe no console o valor das variáveis utilizadas no trecho: sum, lastValue e current.

Após a execução do programa a variável sum contém o valor 55 que, segundo a progressão aritmética, representa o somatório de todos os números inteiros de 1 a 10. Concedendo ao meu código um selo de qualidade INMETRO. Duvida? Soma aí na mão e agradeça que o código não soma os números de 1 a 1000.

Tendo esse código em mente e/ou recorrendo ao mágico universo da computação e a habilidade de rolar a página para cima e para baixo, explico os atributos de uma variável. Um por um.

1. Nome de uma variável

É o nome de batismo de uma variável e é determinado na hora do seu nascimento. Normalmente, a regra para criação de um identificador é a seguinte:

Pagaria milhões para saber disso quando eu era mais novo, mas, além de não ter inteligência, jovens também não têm dinheiro. Eiê.

Essa regra muda de linguagem para linguagem. PHP, por exemplo, comete o crime contra a humanidade ao exigir o símbolo $ no início dos identificadores. Só o Elon Musk consegue superar e dar nomes piores do que o PHP.

Existem variáveis que não possuem nomes. A maioria das variáveis, no entanto, possui. Essas que não devem ser nomeadas, à la Voldemort, são chamadas de anônimas.

No exemplo dado, sum, max, lastValue e current são os identificadores das variáveis. Portanto, seguem a regra de criação de identificadores de Javascript.

2. Tipo de uma variável

O tipo determina a faixa de valores que ela pode armazenar, o tamanho da região de memória alocada e o conjunto de operações definidas para valores do tipo. O tipo int em Java especifica uma faixa de valores de -2147483648 a 2147483647, aloca uma região de 4 bytes e define operações como adição, subtração, multiplicação, divisão e módulo. O tipo boolean especifica os valores true e false, aloca 1 byte na memória e possui as operações relacionais.

Quando uma classe é criada, por exemplo Person, um novo tipo passa a existir e variáveis criadas com o tipo Person e suas operações são os métodos e as funções que manipulam essa classe.

No exemplo citado no início deste artigo, todas as variáveis são do tipo number. Mas como Javascript se trata de uma linguagem fracamente tipada e dinâmica, o tipo das variáveis pode mudar durante a interpretação do código. O trecho a seguir atesta isso:

Algumas linguagens permitem que o tipo da variável mude mesmo após sua declaração.

3. Valor de uma variável

O valor é o conteúdo da região de memória associada a ela. Algumas linguagens, principalmente essas metidas a moderninhas, não permitem que o valor seja alterado após a primeira atribuição. Nesses casos, as variáveis são imutáveis. Podemos dizer que isso é contraditório e podemos alegar que não podem ser chamadas de variáveis.

No código de exemplo inicial, iniciamos respectivamente as variáveis sum e current com os seguintes valores 0 e 1. A cada iteração do laço, atualizamos os valor de sum e incrementamos o valor current. O que deixa bem claro que Javascript tá pouco se lixando para a mutabilidade das variáveis — Na verdade, a linguagem oferece a palavra-chave const para variáveis imutáveis.

4. Endereço de uma variável

É o endereço de memória de máquina ao qual a variável está associada. Muitas linguagens permitem que múltiplas variáveis possuam o mesmo endereço (já ouviu falar em passagem por valor vs. passagem por referência ou referências de ponteiros?). Quando mais de uma variável possui o mesmo endereço, podemos dizer que ela é um apelido da outra variável.

O uso de apelidos pode ser um problemão. Não por conta de bullyings ou coisa parecida, mas por conta da legibilidade. Os apelidos permitem que uma variável tenha seu valor modificado por uma atribuição à outra variável.

Olhem só esse código em C++:

Quando o valor de uma das duas variáveis é alterado o valor da outra é também. Isso acontece porque as duas variáveis possuem o mesmo endereço de memória, como comprovam as linhas 13 e 14.

Java, C# e Javascript também possuem recursos similares ao adotarem a passagem por referência para objetos nas chamadas de funcões.

Já viu a confusão que isso pode causar, né?

5. Escopo de uma variável

O escopo de uma variável é o conjunto de sentenças nas quais ela é visível. Uma variável é visível em uma sentença se ela pode ser usada nela.

Pessoas que programam em Javascript sabem como a falta de entendimento sobre escopo pode avacalhar/corrigir toda a ideia de um programa (sim, estou falando das closures). Para tentar arrumar a bagunça dos escopos do Javascript existem várias maneiras de declarar uma variável: let, const, var e, a mais comumente usada, nenhuma/nadicas… Elas determinam diferentes escopos para a variável em questão.

Um bloco, é uma região do código limitado por tokens definidos pela linguagem escolhida (begin/end, {/}, identação, if/fi e outros) que permite uma seção de código ter suas próprias variáveis, acessíveis somente dentro do bloco, o que minimiza o escopo e melhora o encapsulamento. É o caso da variável current no código de exemplo. Ela pertence exclusivamente ao bloco declarado com a palavra-chave for (da linha 3 até a linha 6). Se tentarmos utilizar a variável fora desse bloco, como mostra a linha 9, o interpretador dá chilique:

Uncaught ReferenceError: current is not defined

Por outro lado, a variável lastValue definida na linha 5 com a palavra-chave var, apesar de também ser declarada dentro do escopo do for, é visível por qualquer sentença após a linha 5, como comprova a impressão da linha 8. Num falei que Javascript avacalhava os escopos?

No outro extremo do espectro dos blocos, estão as variáveis globais. Elas possuem esse nome porque possuem todo o código como escopo. Repito: TODO o código.

Ela não atrai muito a simpatia da comunidade de desenvolvimento de software por conta do encapsulamento, mas tem seu valor.

6. Tempo de vida de uma variável

Geralmente, o tempo de vida de uma variável começa no momento de sua declaração e dura enquanto durar seu escopo. Por isso, há uma relação muito forte entre o escopo e aduração de uma variável.

Uma boa maneira de distinguir os dois atributos é pensar que o escopo é um conceito textual e o tempo de vida é um conceito temporal.

Quando falei sobre o atributo escopo, disse que, no exemplo inicial, a variável lastValue foi declarada no escopo for, dando início ao seu tempo de vida. Contudo, por ter sido declarada utilizando a palavra-chave var, o tempo de vida passa a ser a duração do programa. Vivendo além do próprio escopo de declaração.

A linguagem C++ possui uma funcionalidade que diferencia esses atributos muito bem:

A palavra-chave static, no contexto da linha 4, permite que uma variável de escopo local possua tempo de vida global. Atente para as impressões das linhas 12, 13 e 14. Os valores são diferentes!

A explicação é que as variáveis longLivingCounter e localCounter, apesar de possuírem o mesmo escopo, possuem tempos de vida diferentes. O tempo de vida de localCounter acaba no fim da execução do seu escopo, por isso o seu valor é "reiniciado" no início de cada execução da função. Como tempo de vida de longLivingCounter é a duração da execução do programa, o valor permanece entre as chamadas das funções.

Vejam só este último exemplo em Javascript:

O escopo de counter é o bloco definido pela função add. Tanto que, na linha 10, ao tentar acessar a variável, o interpretador alega desconhecer essa variável. Ainda assim, o tempo de vida dessa variável vai além do fim do escopo de sua declaração, como demonstram as impressões das linhas 6, 7 e 8.

Nossa senhora, esse texto ficou grande. Se você chegou até aqui, bate umas 50 palminhas porque isso aqui deu um trabalho do cão.

Já que tá por aqui sem fazer nada, considere adquirir essa belezura de livro escrito por mim:

Você também pode gostar de:

Pigs don’t fly, never say die