null e none são realmente diferentes?
null e none são realmente diferentes?
Qual a diferença entre null e none? Neste post, exploro como diferentes linguagens tratam a ausência de valor e como ferramentas modernas ajudam a tornar esse uso mais seguro — no fim, tudo depende das escolhas de design.
Na real, qual a diferença entre null e none?
Bem, não sei se vocês já tiveram essa dúvida antes.
Mas antes de iniciar, deixa somente explicar para quem ainda não sabe o que é o null/none.
- null
- nil
- none
- undefined
- NaN
- Maybe
- Nothing
- Option<T>
Apontei uma variação de null/none, que no fim significa ausência de valor, talvez você torça o nariz para undefined, NaN ou Option<T> e cia, para dizer que não é tipo de ausência de valor, mas essa discursão eu reservo para um outro dia.
Agora que definimos que null/none está descrevendo um valor ausente, vamos discorrer pra entendermos se é de fato diferente null e none.
Se você quer uma resposta rápida: Sim, null é diferente de none!
Mas isso por conta de uma escolha da linguagem, mas deixa te explicar...
Pra quem utiliza um python (vamos começar por python) já percebeu que não se usa null para determinar ausência de valor.
Isso porque python construiu a linguagem de forma inteligente, mas não quer dizer que C# ou Java e JS foram mal construídos, mas porque ela nasceu em uma época que toda nova linguagem era C-Like, e todas bebiam da mesma fonte.
Python percebeu que null era quebrado — até mesmo quem criou o null afirmou que null é um erro.
E por quê? Porque null é um ponteiro apontado para a posição 0 da memória, que é protegida pelo sistema operacional, e não permite desreferenciar ou referenciar algo nesse ponto (ponteiro 💡) da memória.
E o que é none? Pasmem vocês, mas também é um ponteiro na memória! Isso porque ele é gravado na heap. Mas praticamente ele é apenas uma normativa da linguagem que diz que: A classe None
é ausência de valor.
O que quero dizer é que ele é uma classe como qualquer outra, bem diferente do que é o null (void*), pois o null aponta diretamente para 0 e a linguagem não controla o meu dado, porque a minha variável pode estar apontando para um endereço totalmente fora do que esperava.
Ex:
Veja que o erro de NullPointerException vai acontecer, não só porque não existe a propriedade no endereço null, mas também porque é uma área protegida e não pode ser desreferenciada.
Ok, eu te trouxe até aqui só pra dizer que:
C# e muitas outras linguagens resolvem isso com Monads, Optionals, Option<T>
, Result<T>
e etc...
Para não ficar muito longo, depois irei falar sobre o que são. Por hora, o none
é uma alternativa elegante a isso.
E como funciona no C#:
Essa simples ? é a mágica. Ela informa ao compilador que essa classe pode ser null
, e com isso, quando fizer um p?.Nome
, não vai dar erro, porque o compilador trata aquele objeto que naquele momento é null
.
Por isso eu digo, none e null nem são tão diferentes!
Porque é decisão da linguagem qual a diferença de que null
aponta direto para memória e none
"não" e é um tipo controlado?
Se consigo adicionar o mesmo comportamento ao null — e não estou dizendo vamos todos continuar usando null.
Na verdade quero dizer, none é só uma derivação de null com o marketing de "somos null-safety".
E por que digo isso?
Isso quebra!
Mas claro, existe uma outra abordagem que é a do Rust, que lida com tudo em tempo de compilação — mas isso aí já deixo pra falar sobre quando tiver mais conhecimento da linguagem. E sim, isso é a perfeição.
A maioria das linguagens vai utilizar uma abordagem semi-defensiva.
Por que digo semi-defensiva? Porque sempre desenvolvemos de forma defensiva quando se trata de null e cia, ex:
if p is not None:
print(p.nome)
Isso resolve, mas sempre lidar com isso assim é feio e verboso. Então temos o null-condition que muitas linguagens utilizam, como no exemplo do C#. E é semi-defensiva, porque você ainda está criando uma condição para o nulo.
Já em uma abordagem pattern-match, dizemos que um dado é isso ou é aquilo.
Ex em V:
Veja que na linha 8, existe uma palavra-chave or, essa palavra-chave é lida com none
/error
.
Como p
foi definido como none
na linha acima, o resultado desse print será 'that was none'
.
É possível lidar com if e com match nesse mesmo caso acima.
Mas a questão aqui é...
O none
tem toda uma arquitetura ao redor para lidar com ausência de valor e bugs em tempo de execução.
E a depender da linguagem, o null
também!
Então o resumo é:
none
não é nada demais, é só um null
controlado.
Posso ter sido propositalmente simplista em relação a
undefined
,maybe
,NaN
e cia, mas tenho motivos para isso. De toda forma espero que tenha apreciado de alguma forma o conteúdo.
Usei IA nesse post para converter o post original da fonte que ta em HTML para markdown.
Aqui é mais do que uma provocação, do que os 10 mandamentos, se tem um entendimento melhor que o meu sobre o assunto adiciona abaixo.
ModerAÍ: https://ddiidev.github.io/ModerAI-Web/ YT: https://www.youtube.com/@mais.foco42 IN: https://www.linkedin.com/in/andreluizss/ IV: https://andrelz.invdual.com/ X: https://x.com/luizdidev