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?
In Go, pointers (mostly) don't go with slices in practice
81–90 of 98 posts
Re: In Go, pointers (mostly) don't go with slices in practice
#82I 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…
Re: In Go, pointers (mostly) don't go with slices in practice
#83Considering 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…
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
#84Earlier 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…
> 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
#85Considering 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.
- 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
#86Earlier 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
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
#87Earlier 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…
Re: In Go, pointers (mostly) don't go with slices in practice
#88Earlier 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?
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
#89Earlier 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.
> 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
#90Earlier 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?
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.