Live data from Hacker News

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

utcc.utoronto.ca

81–90 of 98 posts

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

#81

Earlier quoted context omitted.

For sure. The solution has downsides but it does largely solve the problem. It isn't strictly better than go, but it is an important difference. Mostly off-topic but FWIW "mutable reference into an array" is typically very easy in Rust you just accept a &mut [T]. This also nicely enforces that you don't try to append because that would be wrong 99% of the time.

> Mostly off-topic but FWIW "mutable reference into an array" is typically very easy in Rust you just accept a &mut [T]. I had specifically worded it as "a couple mutable references into an array". How do I take a small number of references into an array, say two or three?

Ah, missed that. You are right, in that case you need to start making some decisions depending on the situation.

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

#82

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 valu…

[deleted]

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

#83
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.

> which makes me wonder: is it simple enough? Obviously not given Go was never simple in the first place. Go was built to be easy — for a certain value of easy. Simple tools are often not easy, and simple programming languages are definitely not easy: they tend to be built out of a small set of very powerful concepts which are directly exposed to the language user, said language user has close to the power of the lan…

Continuing that thought along the line of "Simple made easy," I think ease has a simplicity all its own.

A simple language, e.g. C or lisp, simple in that their grammar is simple, are definitely less easy for the programmer, than say Go. But C is not simple as an experience, since it forces the dev to mentally complect so many concepts in order to get things done: macros, memory management, etc. Lisp is complex in a different way: metaprogamming, DSLs, and deep abstractions are the norm. So simplicity/complexity tends to be something of a whack-a-mole. It's a lower bound, much like the uncertainty principle; you can always add complexity.

Go makes a lot of choices that try to really optimize the user_complexity * language_complexity product.

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

#84

Earlier quoted context omitted.

What about maps? Non-nil maps sure seem like they're "reference types", look at [0]. [0] https://play.golang.org/p/xtY_ASExQzR

"reference types" is a very specific concept from a specific category of languages: types which are always heap-allocated and sitting behind an invisible (and un-interactible) pointer. But Go doesn't have that distinction, and has actual pointers you can use directly. A map is just a heap-allocated structure sitting behind a pointer. If you create a type which is a pointer to a struct, sure you can say you've built a…

> types which are always heap-allocated and sitting behind an invisible (and un-interactible) pointer

> A map is just a heap-allocated structure sitting behind a pointer.

And the difference is?.. Because maps in Go behave exactly as if they were un-referenceable pointers to the hidden, heap-allocated hashtables.

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

#85
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.

There are conventions that help, but they could be made explicit:

- If you don't know where a slice came from (such as getting it passed as an argument), treat it as read-only. Any exceptions should be documented.

- If you're going to mutate a slice, make it a private member of a struct and don't give out direct access to it.

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

#86
post #65

Earlier quoted context omitted.

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

Actually, Pascal has slices

They are just so obscure, I forgot about them and no one uses them. No users, no problems

They are not part of the normal type system. You cannot declare a variable of a type slice. Nor a field. But when a parameter of a function is an (open) array, you can call the function with a slice of an existing array

That avoids most problems

The backing array exists when the function is called, and the function cannot store the slice, so the slice cannot outlive the array. It is like the function borrows the array. Only problem is if the function gets another reference to the array, through a global variable or something, and resizes it

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

#87
post #72

Earlier quoted context omitted.

Go tells you very explicitly how it resizes slices by forcing you to write this: slice = append(slice, item) By merely typing this all the time when you add elements, you intuitively understand that appending can potentially re-allocate the slice data in a totally different location, so any pointers you have taken before the resize are not guaranteed to be pointing to items in the new slice; just the old slice.

> Go tells you very explicitly how it resizes slices by forcing you to write this: No, what most readers intuit from that is that `append` performs no mutation and that this is fine: s2 := append(s1, item) because it looks very much like, say, (def s2 (conj s1 item)) and often it will look like it works, especially at the smaller sizes, or if you never modify (or even use) s1. Except it's absolutely not fine. That's…

the idea that append performs no mutation is fairly insane. its name implies a mutation.

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

#88

Earlier quoted context omitted.

For sure. The solution has downsides but it does largely solve the problem. It isn't strictly better than go, but it is an important difference. Mostly off-topic but FWIW "mutable reference into an array" is typically very easy in Rust you just accept a &mut [T]. This also nicely enforces that you don't try to append because that would be wrong 99% of the time.

> Mostly off-topic but FWIW "mutable reference into an array" is typically very easy in Rust you just accept a &mut [T]. I had specifically worded it as "a couple mutable references into an array". How do I take a small number of references into an array, say two or three?

Off the top of my head you do something like https://play.rust-lang.org/?version=stable&mode=debug&editio...

Yeah you gotta write it out per number of times. Luckily this rarely comes up in this specific form.

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

#89

Earlier quoted context omitted.

> Mostly off-topic but FWIW "mutable reference into an array" is typically very easy in Rust you just accept a &mut [T]. I had specifically worded it as "a couple mutable references into an array". How do I take a small number of references into an array, say two or three?

Off the top of my head you do something like https://play.rust-lang.org/?version=stable&mode=debug&editio... Yeah you gotta write it out per number of times. Luckily this rarely comes up in this specific form.

Wow, that code is as bad as I thought it would be. Yeesh.

> Luckily this rarely comes up in this specific form.

Well, yeah—it would come up rarely because it only solves the problem under very specific circumstances!

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

#90
post #28
post #20

Earlier quoted context omitted.

No, ps still points to s: https://play.golang.org/p/iSjoqGTg20_O var s []int s = append(s, 10, 20, 30) pe := &s[0] ps := &s s = append(s, 50) s[0] = 100 pe2 := &s[0] fmt.Println("s: ", s, ", ps: ", ps, ", pe: ", pe, ", pe2: ", pe2) // s: [100 20 30 50] , ps: &[100 20 30 50] , pe: 0xc0000be000 , pe2: 0xc0000b8030

I don't get why address of slice returned from "append" does not change. Maybe in a trivial program like this the backing array can always be extended in-place, because there in memory fragmentation. Is that still true in an app that has considerable memory pressure and has GC running now and then?

>Maybe in a trivial program like this the backing array can always be extended in-place,

In this example the backing array didn't get extended in-place. The first backing array starts at 0xc0000be000. After the append() call, there's a new backing array, which starts at 0xc0000b8030.

Post reply on HN