Ruby

A beleza do nil em Ruby

13 Jul 2022

Lembro dos meus dias de JavaScript em que perdi horas tentando fazer com que o JavaScript entendesse que 0 não era falso, que existe uma diferença conceitual entre o vazio, entre o nada e entre o 0. Pelo meu background filosófico isso sempre me incomodou, até que conheci como Ruby trata esse tema e fiquei maravilhado.

Na filosofia esse tema é tão sério que já teve até condenação da Igreja Católica contra qualquer pensamento anti-aristotélico que negasse a existência do "nil", com a motivação de preservar a onipotência de Deus. Mas este não é um post sobre filosofia, e sim sobre programação. E em Ruby o nil existe para representar o nada.

Nil não é 0

Você pode pensar: bom, se eu tenho 0 maças, então eu tenho um nada, tenho um nil, certo? Sim, de fato você tem um nada. Mas nem sempre esse é o caso do 0, como quando queremos definir uma temperatura.

0 graus celsius é bastante frio, pelo menos pra mim, então caso você esteja fazendo um software para uma nave de Star Trek, por exemplo, e você quer iniciar a variável da temperatura para só ser definida quando um novo planeta for encontrado, é melhor usar nil do que 0.

temperatura = nil # a variável não foi definida ainda

Nil não é verdadeiro

Existem algumas linguagens que tratam o 0 como falso. E no exemplo acima nós vimos que isso seria um problemão, já que 0 graus Celsius não é um valor falso, é uma temperatura válida, verdadeira, muitos planetas por aí no universo podem ter essa temperatura.

Se estivermos buscando por um planeta com essa temperatura, JavaScript funcionará assim:

if (0) { "Este planeta é o que estamos buscando" }
// => retorna undefined, pois 0 é considerado falso no JavaScript

No Ruby:

"Este planeta é o que estamos buscando" if 0
# => retorna "Este planeta é o que estamos buscando", porque 0 é verdadeiro

No Ruby só temos dois valores falsos: o próprio falso e nil. Mas vale lembrar que falso não é nil. Apenas nil é nil.

false.nil? # => false
nil.nil? # => true

O JavaScript 😅️


Nil não é vazio

Uma outra confusão comum é tratar o vazio como o nada. Se eu tenho uma sacola vazia eu tenho o que colocar dentro da sacola, ao menos conceitualmente.

sacola = []
sacola.nil? # => retorna false

Perceberam a diferença? Eu já tenho alguma coisa, eu tenho uma "sacola", eu tenho uma array. Apenas a existência da sacola dizendo que podem ser colocado coisas dentro dela já nos mostra que existe um Ser. Já existe alguma coisa, apesar de estar vazia. Os itens podem não estar ainda lá dentro, mas sabemos que podemos pensar sobre as coisas que estarão lá dentro. Não é pra isso que o nil serve. O nil serve para literalmente o nada, o desconhecido, quando nem sabemos como, nem sabemos a estrutura de dados.

Existe outro método que utilizamos para saber se algo é vazio:

[].nil? # => retorna false
[].empty? => retorna true

Nil simboliza a não modificação

Em Ruby, o nil também é utilizado para nos dizer quando alguma modificação não foi realizada. Exemplo:

"a".delete!('b') # => retorna nil

Pedimos nesse código para ele deletar todos os 'b' que existem dentro de 'a' e modificar o valor original (por causa do !). Bom, não tem nenhum 'b' lá dentro, então nenhuma modificação foi feita, retornando o nil.

Isso nos faz ficar alertas, porque Ruby escolheu esse design que impede o encadeamento de métodos. Por exemplo:

'a'.delete!('b').upcase
# => retorna undefined method `upcase' for nil:NilClass

O motivo é que como o método delete! não fez nenhuma modificação (já que não existe a letra b na string), então ele retorna nil, e só então ele chama o método upcase que não funciona em nil, apenas em strings. A solução para isso é usar métodos que retornam novos objetos (sem o !, por exemplo), o que vai ter uma perda de performance, mas permitirá encadear métodos da sua preferência.

Espero que vocês tenham gostado dessa jornada conceitual da mesma forma que eu gostei. Até a próxima postagem.

Receba atualizações por e-mail

Sempre que tiver novidades por aqui vou enviar aos inscritos.

Entre na conversa

Criei uma postagem lá no LinkedIn para receber comentários:

Comente