Hacker News new | ask | show | jobs
by TheDong 2190 days ago
Pointers in go aren't a signal for optionality, they're a signal for stack or heap or optionality. They also don't play nice with interfaces.

Let's say I have a hashmap that returns a `&T` and I have a `func foo(s Stringer)`. Because 'Stringer' is an interface, it's possible for it to take both `T` and `&T` without a compile-time complaint.

In addition, I may wish to have my function `bar(t &T)` always take a pointer because I want the object to exist on the heap, or to be able to mutate its value for the caller.

Since pointers mean so many other things, they're not a good way to have a compile-error indicate optionality.

On the other hand, if my caller does `hm.Get` and gets an `Option<s: Stringer>`, it's clear what to do to pass it to foo, and if it's an `Option<&T>`, it's clear both that I want a pointer, and that it should be checked / unwrapped.

I agree that `T` / `&T` would be just as powerful as option types in go (without sum types) if pointers didn't already have other substantial meaning, and if they could sensibly interact with interfaces.

As it stands, I think you're off the mark though.

(note: All the asterisks are & because I dunno how to escape stuff on hn)

1 comments

> Pointers in go aren't a signal for optionality, they're a signal for stack or heap

No, a pointer in Go doesn't mean that it's on the heap. The compiler keeps it on the stack if it's safe to do so, regardless of whether you're using pointers.

You can even write code like `t := new(T); t.Foo()` that very much looks like you're allocating on the heap, but it can stay on the stack, yet t is then a pointer to the stack.

Unlike C, you don't need to worry about the heap-vs-stack in Go. It's never even mentioned in the language spec as a concept people need to be concerned with. It's an implementation detail.

> Unlike C, you don't need to worry about the heap-vs-stack in Go. […] It's an implementation detail.

I'm really surprised to read that: yes a beginner can get his code working without wondering about stack vs heap (and that's one of the big reason why Go is easier to learn than Rust for people coming from non-system language), but as soon as you care about performance (which many Go users do!), you need to write code that reduces allocations to the minimum, because Go's allocator is really slow (compared to Java for instance). Interestingly enough, doing so forces you to think about the ownership and lifetime of your objects, like you'd do in C (or Rust).

The great thing about Go is that you don't need to think about allocations or lifetimes until you care about performance. Memory management is optimization in Go, while in C, C++, Rust, etc it's required to get a program to compile (of course you can "opt in" to easy memory management in those languages by using some kind of GC library, this is vanishingly rare--presumably developers would rather just use a language that was designed for GC). If you're at the point where your Go code is so performance sensitive that you're optimizing memory more often than not, it probably makes sense to be using Rust, but these cases are rare for the kinds of applications I tend to write (which is sad because I actually really enjoy using Rust).
Absolutely (well at least for Rust, because for C it's not required for it to compile: the code will compile to some broken garbage that will either crash at runtime, be vulnerable to exploits or burn your hard drive, depending on the mood ;).

I just found surprising to see a core person of Go declaring heap vs stack allocation to be “implementation detail”. Because if it was, that would mean that my carefully crafted zero-alloc code could become full of allocations one day because the underlying implementation changed! Obviously they don't want their users to be afraid of that.

This is not entirely true. You can exhaust stack headroom by calling functions with very large pass-by-value structs. In these situations, you are then forced to use a pointer, which results in heap allocation.