
Go Nil Pointers and Rust - tschellenbach
https://getstream.io/blog/fixing-the-billion-dollar-mistake-in-go-by-borrowing-from-rust/
======
dagenix
A minor nit: There is a major difference between Rust references and C++
references - while both are guaranteed to point at something, only a Rust
reference is guaranteed to point at something valid. A C++ reference can point
at an already freed object if you aren't careful which can be worse than a
NULL pointer dereference since this can cause silent corruption.

~~~
saurik
Can you define better "guaranteed"? If you take a NULL pointer and dereference
it you get a null reference. I realize the language standard insists this
isn't possible, and so compiler developers have started feeling justified in
saying "if (&myref == NULL)" is nonsense they can "optimize out" (as if I
somehow typed that by mistake :/...); but that is just the compiler making an
unwarranted and clearly incorrect "assumption": _nothing_ in any of the
language standard, the compiler, or the runtime "guarantees" that references
point at something. If dereferencing a pointer was required to do a one byte
read from the address that could not be elided by the compiler, or
automatically injected the moral equivalent of "if (myptr == NULL)
std::terminate();", that would be an entirely different story; but, as it
stands, a dereference from a pointer to a reference is nothing more than a
blind type assertion by the developer, and so there is no reason to believe a
reference is somehow any less likely to be NULL than a pointer the developer
always thought would point to something.

~~~
saagarjha
> compiler developers have started feeling justified in saying "if (&myref ==
> NULL)" is nonsense they can "optimize out" (as if I somehow typed that by
> mistake :/...); but that is just the compiler making an unwarranted and
> clearly incorrect "assumption": nothing in any of the language standard, the
> compiler, or the runtime "guarantees" that references point at something

I don't see how there is nothing guaranteeing that your references are
nonnull. My understanding was that the standard prevents you from having a
null reference because the methods of trying to generate one are codified as
illegal or performing undefined behavior. Am I wrong here, or misunderstanding
what you're trying to say?

------
noncoml
Rust has algebraic data types. That’s completely different than the proposed
solution for Go, which is pretty much what Kotlin does. And IMHO its a
bandaid.

ADTs are the way to go. If Go had ADTs I would pick it over Rust in a
heartbeat, as I personally don’t care much about not having a GC, and think
go-routines are superior to async/await.

~~~
ZirconiumX
This sounds like a fit for OCaml with either Async or preferably Lwt. ADTs are
natural in OCaml, and you can even have Generalised ADTs which can encode ADTs
into the type system.

Granted, the main downside of OCaml is it still being single threaded. That
can be worked around, but it depends on your workload.

------
SamReidHughes
People complaining about nil haven't thought the problem through. It makes the
language way more complicated if variables can't sit in an uninitialized state
(with a default value of nil or zero instead of random bits). Basic stuff like
named return values no longer work. Slices can only contain certain special
zeroable types.

The right thing to do is to know statically in your code whether a variable
can be nil, or can't. Don't put stupid little nil checks in every function,
but maybe do so when storing a field, e.g. to ensure an object holds valid
state.

If your biggest problem is surprise nil pointer values, then that's good for
you, because they're relatively easy bugs to track down.

~~~
oconnor663
> Basic stuff like named return values no longer work.

If Rust hypothetically wanted to add named return values, I think the way
they'd do it is have the compiler check that all codepaths through the
function initialize the returns. In general rustc is happy to let you declare
uninitialized variables, and even partially initialize them field-by-field, as
long as it can prove to itself that everything's fully initialized by the time
you read it.

~~~
SamReidHughes
This won't work the way Go does it, or else you end up with fiddly little
rules about when you're allowed to take addresses of variables and such.

------
kjeetgill
I looked for it in the article but I didn't see see it anywhere: In go you can
have methods that execute with nil receivers. In practice this makes nil in go
very different than null I'm java.

func main() { var a _A a.getB().getM() }

type A struct { B _B; }

func (a _A) getB()_ B { log.Println("getB") if a != nil { return a.B; } return
nil }

type B struct { M string; }

func (b *B) getM() string { log.Println("getM") if b != nil { return b.M; }
return "" }

Everything is nil but they both got executed! Obviously, you should use this
selectively, but it's there!

Algebraic Data Types always seemed more elegant when I've seen them in other
languages, anyone have anything but positive things to say about them?

~~~
calebh
Isn't this just the Maybe monad without any benefits of abstraction?

------
ihsw2
I do like the idea of explicit non-nil pointers. While I have refactored code
to explicitly exclude all uses of pointers unless absolutely necessary and (as
mentioned in the article) studiously check for nil when receiving interfaces
and pointers, it feels hacky as hell. Non-nil pointers would bring us halfway
to a better place IMHO.

