Live data from Hacker News

In Go, pointers (mostly) don't go with slices in practice

utcc.utoronto.ca

61–70 of 98 posts

Re: In Go, pointers (mostly) don't go with slices in practice

#61
post #31

Earlier quoted context omitted.

> Rust has created a weird perception that memory safety equals safety. I think it's a bit more than that. They're also riding on the static typing trend that's happening right now, so type-safety is also part of the equation. From the website: > A language empowering everyone to build reliable and efficient software. > Reliability: Rust’s rich type system and ownership model guarantee memory-safety and thread-safety…

> They're also riding on the static typing trend that's happening right now, so type-safety is also part of the equation I think the "static typing trend" is a product of Rust and Go showing people that static typing doesn't have to be cumbersome like it was in 90s-00s Java, C++, and C#. Indeed, I suspect that the quality of life improvements that Java, C#, and C++ made also improved the stock price of static typing…

That wasn't my intended meaning, I don't think static typing is a "fad". I think the "new" typed languages (Go, Rust, Typescript) are more ergonomic than 90s-00s Java, C++, C#, as you said. This is also forcing them to improve, with features like type inference, sealed classes, records. I also think that the combination of gradual typing and type inference is playing a big role in the adoption.

However, I called static typing a "trend", and I'll try to explain why. I think attempts to type Python, JS, Ruby and the popularity of Go and Rust are the natural consequences of people departing from the Java/C++ ecosystem 10-20 years earlier (for good reasons). Now they are rediscovering the good parts of this ecosystem (ease of deployment with binaries/fat jars, static typing, performance). Since Twitter, Github, Youtube, Shopify, Instagram, etc have all that code around, they are going to either improve it, or try to migrate from it. For example, Shopify is working on a compiler to native for Ruby based on LLVM https://sorbet.org/blog/2021/07/30/open-sourcing-sorbet-comp.... Instagram is working on a performance-oriented CPython fork https://github.com/facebookincubator/cinder. Twitter, from what I understand, went back to Java, going through Scala first (which is another example of "better type system"). KhanAcademy is migrating services from a Django monolith to Go services https://blog.khanacademy.org/half-a-million-lines-of-go/. Whatsapp even had a project to do a statically typed "Erlang 2".

The "trend" here is that some companies that use "new" dynamic languages in the 00s are now very large companies that have enough money to invest in language, tooling and things like that.

Re: In Go, pointers (mostly) don't go with slices in practice

#62
post #41
post #34

Earlier quoted context omitted.

Does that mean that a) the pointer to the single element is only invalidated on “append” if the slice has no more capacity (this is how C++ vectors work), or b) does the fact that there’s an active reference into the slice always cause a reallocation (copy-on-write style)? If it’s the former, we’re literally in the C++ iterator invalidation nightmare, only without the debugging tools.

The array is only reallocated when it runs out of space. There is no magic about the "old" array. The GC just won't collect it, as long as a pointer to it exists. I don't think there are many reasons, if any at all, to keep a pointer to an array element of a slice around in Go. Usually I only get the address of an array element only when passing it to some C code or doing some low level manipulation, but then I don't…

Thank you for clarifying this. I was scratching my head reading this discussion, wondering why one would do this in the first place.

Re: In Go, pointers (mostly) don't go with slices in practice

#63
post #61

Earlier quoted context omitted.

> They're also riding on the static typing trend that's happening right now, so type-safety is also part of the equation I think the "static typing trend" is a product of Rust and Go showing people that static typing doesn't have to be cumbersome like it was in 90s-00s Java, C++, and C#. Indeed, I suspect that the quality of life improvements that Java, C#, and C++ made also improved the stock price of static typing…

That wasn't my intended meaning, I don't think static typing is a "fad". I think the "new" typed languages (Go, Rust, Typescript) are more ergonomic than 90s-00s Java, C++, C#, as you said. This is also forcing them to improve, with features like type inference, sealed classes, records. I also think that the combination of gradual typing and type inference is playing a big role in the adoption. However, I called stat…

Makes sense. Thanks for clarifying!

Re: In Go, pointers (mostly) don't go with slices in practice

#64
post #3

Well, of course slices work that way. Think about what happens if you have a reference to a slice in an array and you shrank the array to 0. You've just created a dangling pointer. In Go, you get a stable version of the old data, and the garbage collector tracks that you still have a reference to it. This is safe, but confuses some people. In Rust, the borrow checker won't let you modify the array while you have a re…

In Pascal, there are no slices

No slices, no problems

If you need to work with a part of a string, you can make two ordinary integer variables for offset and length

Re: In Go, pointers (mostly) don't go with slices in practice

#65
post #3

Well, of course slices work that way. Think about what happens if you have a reference to a slice in an array and you shrank the array to 0. You've just created a dangling pointer. In Go, you get a stable version of the old data, and the garbage collector tracks that you still have a reference to it. This is safe, but confuses some people. In Rust, the borrow checker won't let you modify the array while you have a re…

In Pascal, there are no slices No slices, no problems If you need to work with a part of a string, you can make two ordinary integer variables for offset and length

Cool

Re: In Go, pointers (mostly) don't go with slices in practice

#66
I love Go, my favourite language. But I've been bitten before by passing slices around and then finding out that they got disassociated and are now pointing at two different backing arrays without telling me.

I kinda know enough now to avoid this, but I have to be careful and remind myself it's a possibility.

I'd love some built-in method to be able to tell whether altering a value in slice A will also alter the value in slice B (i.e. whether A and B are referring to the same backing array). As far as I'm aware there's no easy way of doing this in Go.

Re: In Go, pointers (mostly) don't go with slices in practice

#67
post #45

Considering the confusion of the author, it seems like not all junior programmers can understand Go, which makes me wonder: is it simple enough? One pitfall is when getting a slice by value in a function. You cannot be sure that someone is not going to pass you a slice into a buffer that they themselves use, so you have to be careful when appending - someone might be using that buffer and you’ll be writing over it.

I don't feel its a matter of complexity per se, more like bad UX. We could imagine exposing why this doesn't work to end users instead oh hiding behind a leaky abstraction.

Re: In Go, pointers (mostly) don't go with slices in practice

#68

> Honestly, this is a strange and peculiar situation, although Go programmers have acclimatized to it. To programmers from other languages, such as C or C++, the concept of pointers to dynamically extensible arrays seems like a perfectly decent idea that surely should exist and work in Go. Well, it exists, and it "works" in the sense that it yields results and doesn't crash your program, but it doesn't "work" in the…

I agree that it is better than C and C++ but not much better.

C and C++ are "It is very easy to make this mistake which leads to undefined behaviour and a maybe incorrect program."

Go is "It is very easy to make this mistake which leads to a maybe incorrect program."

Yes, better! But the problem is still there. I much prefer the Rust solution where there is no common mistake.

Re: In Go, pointers (mostly) don't go with slices in practice

#69
post #15
post #7

Earlier quoted context omitted.

Yep, that immediately stood out to me too. s is a local variable (or global, doesn't matter). ps simply points to that local variable. You can modify the local variable all day long and ps will still point to it, not some old version of it.

the line `s = append(s, 50)` redefines what "s" actually is. And after this line `ps` points to some previous version of what "s" used to be.

`s` is some value that occupies some memory, starting at say address 1000. `ps` contains the address of `s`, 1000. It will do this no matter what you put in memory at address 1000. You can assign new values to `s`, e.g. via append, but ps will still point to its address, 1000.

The confusion stems from the fact that a slice object contains a pointer in itself, pointing to a backing array, thus adding an additional layer of indirection. Append will return a new slice that may point to a different backing array. This doesn't matter, because you put the new slice in the memory location pointed at by ps, 1000.

This is not so different from pointer pointers. If you have `int i = 0; int pi = &i; int *ppi = π` you can change `pi` (analogous to the slice) to your heart's content and `ppi` will reflect the changes.

Re: In Go, pointers (mostly) don't go with slices in practice

#70
post #32

Earlier quoted context omitted.

> This is safe, but confuses some people. Rust has created a weird perception that memory safety equals safety. Language is a tool and it should work with me: it is extremely important that my understanding of what the program should do aligns with what it actually does. The way you describe go's behavior is "takes snapshot of the underlying data", which usually means "deep copy container". Taking a pointer/reference…

This is how I think about Go slices (may help other understand them). A slice itself is just a window into a backing array of fixed size. The slice carries three data members. The pointer to the backing array and its remaining capacity and the length of the slice data. Typically slices are passed around by value but you can take their address and modify a "shared" slice. The built-in append() returns a new slice by v…

> I've constructed similar utility types in C and find them quite convenient. It's very convenient to have the distinction between the backing memory (array) and a slice viewing a portion of it instead of just a dynamic array.

Of course that's convenient, the issue of Go's slices is that they act as both a dynamic array and a slice viewing a portion of one. The two uses conflict with one another, and the interactions are full of traps.

Post reply on HN