Hacker News new | ask | show | jobs
by hnlmorg 469 days ago
A nil pointer isn’t a type. It’s a pointer to a type and that type hasn’t been created. In short, it’s an initialisation problem rather than a type system problem.

Where “references” differ is you have to initialise the type to get a reference. In Python and Typescript, you don’t create naked pointers. You create structs then pass that reference in functions.

The problem with Go is that you can create those naked pointers and then you need to remember to create your struct and then point that pointer to the struct. And you’re sometimes you’re incentivised to write code this way because Gos garbage collector needs to do more work than if you create pointers adhoc after (like references). But you can use pointers like references if you wanted too.

So there isn’t really a direct comparison with languages like Python and Typescript because they don’t have the same primitive to begin with.

There are benefits to Gos approach: you get more control over memory usage as well as improved performance. But like any idiom, it comes with disadvantages too. And the reason Go panics is because the alternative is the risk of silent memory corruption, which is what a lot of other languages can suffer from with pointers. Though this isnt to say that there are also languages that do solve this problem in a much better way too. But they’re are also a completely different language to Python and Typescript again too.

So the comparisons to Python and Typescript simply don’t work for this type of problem.

1 comments

There is no practical difference between

    function useFoo(f: Foo) { f.Use() }
    var foo: Foo
    useFoo(foo)

and

    func useFoo(f *Foo) { f.Use() }
    var foo *Foo
    useFoo(foo)
in this context. References vs pointers are equivalent here.
Actually there is. In your first example you’re passing an object as a reference, and in your second example you’re creating an empty pointer with no object attached.

A better example will be:

   foo := Foo{}
   useFoo(&foo)
That go code would be functionally equivalent to your Typescript code and if everyone used pointers like references in Go, like the above code, then you wouldn’t have any nil pointer bugs.

Nil pointer bugs happen when you need to use pointers as pointers. (Shock horror!) And sometimes you do need a pointer with no object attached when solving specific problems are aren’t well suited for Typescript.

Python and Typescript doesn’t have pointers. Those languages made different trade offs so they lose performance and memory management controls as a result.

It’s no secret that Python needs to call FFIs to (for example) C++ code when performance and memory management concerns arise. Likewise with node too. In fact I’m in the process of debugging a 3rd party Rust library for Node that’s not handling pointers correctly and thus causing sporadic crashes of the node runtime. And that Rust library only exists in the first place because JavaScript doesn’t have primitives to write the required code natively in node at the performance required for scale.

Maybe WASM will be the saviour here. But it feels like we are now just piling on more abstractions between the code and CPU rather than trying to learn how to use our existing set of tools better.

No… I’m sorry I don’t have time to explain TS now. But that’s not what’s happening at all. What you’re proposing would be the equivalent of ‘var foo = new Foo()’. The default value in TS is undefined, which behaves generally isomorphically to nil.
I really really disliked working with undefined in Typescript. You might dislike the way Go throws an exception with nil pointers, but undefined types go too far the other way and can be a cause for subtle hard-to-find bugs if you’re not doing exactly the same kind of null checks.

That said, Im sure there are better ways of handling undefined types in Typescript than I was doing. I’m certainly not an expect in Javascript nor Typescript. Though a large part of that reason is because there are far far far too many design choices in those languages that really rub me the wrong way, so I usually limit my Javascript/Typescript usage the bare minimum I can get away with.

That all said, I will say I found Typescript to be a massive improvement over vanilla Javascript. It’s a pity we can’t just do away with JS completely and have TS run everywhere instead.

python does have pointers under the hood. objects are passed via pointers. i think the implementation is tagged values in order to support dynamic typing and passing non-pointer values efficiently. but if there was no object tagging the runtime would be very similar to go. both have objects passed around as pointers using some form of garbage collection to handle memory safety.

the optional static type checking in python gives you a stronger typing than what golang does because you don't have to type everything as (None | Foo) and presumably its a type error to perform Foo operations on a (None | Foo) type.

> python does have pointers under the hood. objects are passed via pointers.

Of courses there’s pointers under the hood. It’s a runtime built in C++.

But that doesn’t mean that Python -the language not the runtime- has pointers itself.

> the optional static type checking in python gives you a stronger typing than what golang does

“Stronger” isn’t the term you’d want to use there. Python is not more strongly typed than Go just by virtue of it being more a dynamic language.

I do agree that the Go type system is pretty inflexible though.