
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 porque? por que 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 é gravada 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 aponda 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 resolve 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, ele informa ao compilador que essa classe pode ser null, e com isso quando fizer um p?.Nome
não vai dá erro, porque o compilador trata aquele objeto que naquele momento é null.
Por isso eu digo, none e null nem é tão diferente!
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 porque digo isso?

Mas claro, existe uma outra abordagem que é a do Rust, que lida com tudo em tempo de compilação, mas isso ai já deixo pra falar sobre quando tiver mais conhecimento da linguagem e sim, isso é a perfeição.
A maioria das linguagens vão utilizar uma abordagem semi-defensiva.
Porque 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 ta 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.