3 ms·
>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
by Thorrez 5y ago
>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 sense of doing what you'd actually want.
I think it works in the same way as a pointer to std::span in C++. (Or pointer to std::string_view with the exception that std::string_view doesn't allow modification of the elements.)
I guess the difference is that std::span doesn't let you append to the backing array through the std::span directly. So with C++ you have to write more code which makes it clearer what's happening.
- edflsafoiewq 5y agoC++ has std::vector, which is one level of abstraction above a slice; you push to a vector, and maybe the backing slice changes, but it's still the same vector. Go is unusual in not having a equivalent of vector.
- pjmlp 5y agoNot really, if reallocation takes place. So if you got a pointer to a vector element, it now points to garbage.
- simiones 5y agoI guess the difference is this: C++: std::vector<int> v {1, 2, 3}; void foo(std::vector<int> *ref) { ref.push_back(4); } foo(&v); //v[3] == 4 is true here Go: v := []int{1, 2, 3} func foo(ref *[]int) { append(ref, 4) } foo(&v) //v[3] == 4 may or may not be true here. Pointers to elements in the vector do indeed have the same problems both in Go and C++ (except for memory safety).
- pjmlp 5y agoAh ok, although for the audience not versed in C++ the correct code is, void foo(std::vector<int> *ref) { ref->push_back(4); } foo(&v); or void foo(std::vector<int> &ref) { ref.push_back(4); } foo(v);
- simiones 5y agoOops, right, bit rusty on C++...
- tialaramex 5y ago> //v[3] == 4 is true here Note that C++ std::vector has an operator overload so this is actually just calling the method named operator[] on the object v and that method returns you a reference to the object in the backing array if in fact it is a suitable size (no checks are made). In particular if foo doesn't for any reason extend the vector then our program now has Undefined Behaviour. This is not merely the C syntactic sugar array subscript operation v[3] == *(v+3) as the vector is not necessarily just a backing array pointer and some magic. In contrast Go is really offering array syntax for this slice, that's the built-in array subscript operation and it cares whether v[3] exists when you try to compare it to 4.
- simiones 5y agoI'm not sure I understand how this is relevant. In C++, arr[non_existent_index] is UB both if arr is an std::vector and if it is a C-style array. In Go it's a runtime error instead. Sure, std::vector::operator[]() is not just syntax sugar for *(v+i), but I don't think any of this is relevant for the discussion at hand, unless I'm missing something.
- leaveyou 5y agoappend(ref, 4) // error: first argument to append must be slice append(*ref, 4) // error: append(*ref, 4) evaluated but not used this is the correct version and it also removes the incertitude: *ref = append(*ref, 4) https://play.golang.org/p/-xDqaxvqWhm https://play.golang.org/p/-xDqaxvqWhm
- Thorrez 5y agoYes, std::vector and slice are different. My point is that a slice is similar to std::span. With both slice and std::span, = does a shallow copy of just 2 or 3 pointers. With std::vector = does a deep copy of every element, you have 2 distinct backing arrays. Go forces you to use copy() and append() and rely on the garbage collector to make a slice fill the roll of std::vector. IMO it leads to some confusing code.