Are you sure this is what's happening? Looks to me like the slice object is returned by value, and the array was always on the heap. See https://go.dev/play/p/Bez0BgRny7G (the address of the slice object changed, so it's not the same object on the heap) Sure, Go has escape analysis, but is that really what's happening here? Isn't this a better example of escape analysis: https://go.dev/play/p/qX4aWnnwQV2 (the object…
Go's escape analysis and why my function return worked
31–40 of 76 posts
Re: Go's escape analysis and why my function return worked
#32Earlier quoted context omitted.
> This seems to be a persistent source of confusion. Why? It is the same as in C. #include #include struct slice { int *data; size_t len; size_t cap; }; struct slice readLogsFromPartition() { int *data = malloc(2); data[0] = 1; data[1] = 2; return (struct slice){ data, 2, 2 }; } int main() { struct slice s = readLogsFromPartition(); for (int i = 0; i
The point the GP was making was that the following Go snippet: func foo() { x := []int { 1 } //SNIP } Could translate to C either as: void foo() { int* x = malloc(1 * sizeof(int)); x[0] = 1; //... } Or as void foo() { int data[1] = {1}; int *x = data; //... } Depending on the content of //SNIP. However, some people think that the semantics can also match the semantics of the second version in C - when in fact the sem…
Re: Go's escape analysis and why my function return worked
#33Are you sure this is what's happening? Looks to me like the slice object is returned by value, and the array was always on the heap. See https://go.dev/play/p/Bez0BgRny7G (the address of the slice object changed, so it's not the same object on the heap) Sure, Go has escape analysis, but is that really what's happening here? Isn't this a better example of escape analysis: https://go.dev/play/p/qX4aWnnwQV2 (the object…
Re: Go's escape analysis and why my function return worked
#34Earlier quoted context omitted.
I don't see how this is coming at go "from below". even in C, the concept of returning a pointer to a stack allocated variable is explicitly considered undefined behavior (not illegal, explicitly undefined by the standard, and yes that means unsafe to use). It be one thing if the the standard disallowed it. but that's only because the memory location pointed to by the pointer will be unknown (even perhaps immediately…
The confusion begins the moment you think Go variables get allocated on the stack, in the C sense. They don't, semantically. Stack allocation is an optimization that the Go compiler can sometimes do for you, with no semantics associated with it. The following Go code also works perfectly well, where it would obviously be UB in C: func foo() *int { i := 7 return &i } func main() { x := foo() fmt.Printf("The int was: %…
Re: Go's escape analysis and why my function return worked
#35Re: Go's escape analysis and why my function return worked
#36I don’t think this is confusing to the vast majority of people writing Go. In my experience, the average programmer isn’t even aware of the stack vs heap distinction these days. If you learned to write code in something like Python then coming at Go from “above” this will just work the way you expect. If you come at Go from “below” then yeah it’s a bit weird.
Back in Python 2.1 days, there was no guarantee that a locally scoped variable would continue to exist past the end of the method. It was not guaranteed to vanish or go fully out of scope, but you could not rely on it being available afterwards. I remember this changing from 2.3 onwards (because we relied on the behaviour at work) - from that point onwards you could reliably "catch" and reuse a variable after the scope it was declared in had ended, and the runtime would ensure that the "second use" maintained the reference count correctly. GC did not get in the way or concurrently disappear the variable from underneath you anymore.
Then from 2008 onwards the same stability was extended to more complex data types. Again, I remember this from having work code give me headaches for yanking supposedly out-of-scope variable into thin air, and the only difference being a .1 version difference between the work laptop (where things worked as you'd expect) and the target SoC device (where they didn't).
Re: Go's escape analysis and why my function return worked
#37I don’t think this is confusing to the vast majority of people writing Go. In my experience, the average programmer isn’t even aware of the stack vs heap distinction these days. If you learned to write code in something like Python then coming at Go from “above” this will just work the way you expect. If you come at Go from “below” then yeah it’s a bit weird.
Go has been my primary language for a few years now, and I’ve had to do extra work to make sure I’m avoiding the heap maybe five times. Stack and heap aren’t on my mind most of the time when designing and writing Go, even though I have a pretty good understanding of how it works. The same applies to the garbage collector. It just doesn’t matter most of the time. That said, when it matters it matters a lot. In those t…
Re: Go's escape analysis and why my function return worked
#38Re: Go's escape analysis and why my function return worked
#39Shameless plug, if one wishes to track down allocations in Go, an allocations explorer for VS Code: https://marketplace.visualstudio.com/items?itemName=Clipperh...
Re: Go's escape analysis and why my function return worked
#40Earlier quoted context omitted.
The confusion begins the moment you think Go variables get allocated on the stack, in the C sense. They don't, semantically. Stack allocation is an optimization that the Go compiler can sometimes do for you, with no semantics associated with it. The following Go code also works perfectly well, where it would obviously be UB in C: func foo() *int { i := 7 return &i } func main() { x := foo() fmt.Printf("The int was: %…
ok, I'd agree with you in that example a go programmer would expect it to work fine, but a C programmer would not, but that's not the example the writer gave. I stand by my statement that the example the writer gave, C programmer would expect to work just fine.
As the author shows in their explanations, they thought that the backing array for the slice gets allocated on the stack, but then the slice (which contains/represents a pointer to the stack-allocated array) gets returned. This is a somewhat weird set of assumptions to make (especially give that the actual array is allocated in a different function that we don't get to see, ReadFromFile, but apparently this is how the author thought through the code.