Separating the concept of pointers and nullable types is one of the things that I think go having from the beginning would have made it a much better language. Generics and sum types are a couple of others.
All reference types should be able to take a null value.
It's impossible to write complex and performant programs without null.
It's impossible to write complex and performant programs without pointers.
References always hold a memory address in a linear address space. (Not even true in C!)
Every type is comparable.
Every type is printable.
Every type should derive from the same common type.
All primitive types should support all kind of arithmetic the language has operators for.
The only way to extend an existing type is to inherit from it.
What else?
Well, I'd rather not copy around a multi-hundred-megabyte (or gigabyte) 3D object around to be able to poke its parts at will.
I'll also rather not copy its parts millions of times a second.
While not having pointers doesn't make impossible, it makes writing certain kinds of problems hard and cumbersome.
Even programming languages which do not have pointers (cough Java cough), carry pointers transparently prevent copying and performance hits.
The operations written in a program must literally represent the operations the computer will execute.
This one stops being true on high-level languages at the level of x86 assembly.
And in some languages, where you only operate on values, and never worry about where something is stored, allocation is just an implementation detail.
Example in C:
void fun(void) {
int a[16];
for (int i = 0; i < sizeof(a); i++)
{
a[i] = 1;
}
}I have allocated and referred to memory without pointers here.
It’s 2024, every type is jsonable!
Well, clearly there is a need for a special value that is not part of the set of legal values. Things like std::optional etc. are of course less performant.
If I can dream, all of this would be solved by 72-bit CPUs, which would be the same as 64-bit CPUs, but the upper 8 bits can be used for garbage collection tags, sentinel values, option types etc.
There's a neat trick available here: If you make zero an illegal value for the pointer itself, you can use zero as your "special value" for the std::optional wrapper, and the performance overhead goes away.
This is exactly what Rust does, and as a result, Option<&T>, Option<Box<T>>, etc are guaranteed to have zero overhead: https://doc.rust-lang.org/std/option/index.html#representati...
https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/cheri...
Address space is 64bit, pointers are 128bit, and encode the region the pointer is allowed to dereference. And there's a secret 129th bit that doesn't live in the address space that gets flipped if the pointer is overwritten (unless it's an explicit instruction for changing a pointer)
And the dismissive tone of some people including Ian. But to be fair before Rust there was definitely this widespread myth in the dev hivemind that nullable pointers is just the cost of performance and low level control. What’s fascinating is how easy and hindsight-obvious it was to rid code of them. I’ve never had to use pointers in Rust and I’ve worked on quite advanced stuff.