Remix.run Logo
foldr 4 days ago

What confuses people is

    int *foo(void) {
        int x = 99;
        return &x; // bad idea
    }
vs.

    func foo() *int {
        x := 99
        return &x // fine
    }
They think that Go, like C, will allocate x on the stack, and that returning a pointer to the value will therefore be invalid.

(Pedants: I'm aware that the official distinction in C is between automatic and non-automatic storage.)

knorker 4 days ago | parent [-]

Yes. That's escape analysis. But this is not what OP did.

What you wrote is not the same in C and Go, because GC and escape analysis. But 9rx is also correct that what OP wrote is the same in C and Go.

So OP almost learned about escape analysis, but their example didn't actually do it. So double confusion on their side.

foldr 4 days ago | parent [-]

Well, my point is that escape analysis has nothing to do with it at the semantic level. So it's actually just 'because GC'. You don't need the concept of escape analysis at all to understand the behavior of the Go example.

knorker 3 days ago | parent [-]

Yeah. That's what I said.

foldr 3 days ago | parent [-]

I mean that escape analysis has nothing to do with my example either, in terms of understand the semantics of the code (so I’m disagreeing with the ‘because GC and escape analysis’ part of your comment).

knorker 3 days ago | parent [-]

Your https://news.ycombinator.com/item?id=46234206 relies on escape analysis though, right?

Escape analysis is the reason your `x` is on the heap. Because it escaped. Otherwise it'd be on the stack.[1]

Now if by "semantics of the code" you mean "just pretend everything is on the heap, and you won't need to think about escape analysis", then sure.

Now in terms of what actually happens, your code triggers escape analysis, and OP does not.

[1] Well, another way to say this I guess is that without escape analysis, a language would be forced to never use the stack.

foldr 3 days ago | parent [-]

Escape analysis clearly isn’t part of the semantics of Go. For that to be the case, the language standard would have to specify exactly which values are guaranteed to be stack allocated. In reality, this depends on size thresholds which can vary from platform to platform or between different versions of the Go compiler. Is the following non-escaping array value stack allocated?

    func pointless() byte {
        var a byte[1024]
        a[0] = 1
        return a[0]
    }
That’s entirely up to the compiler, not something that’s determined by the language semantics. It could vary from platform to platform or compiler version to compiler version. So clearly you don’t need to think about the details of escape analysis to understand what your code does because in many cases you simply won’t know if your value is on the stack or not.
knorker 3 days ago | parent [-]

While you are of course 100% correct, in the context of discussing escape analysis I find it odd to say that it's essentially not "real".

Like any optimization, it makes sense to talk about what "will" happen, even if a language (or a specific compiler) makes no specific promises.

Escape analysis enables an optimization.

I think I understand you to be saying that "escape analysis" is not why returning a pointer to a local works in Go, but it's what allows some variables to be on the stack, despite the ability to return pointers to other "local" variables.

Or similar to how the compiler can allow "a * 6" to never use a mul instruction, but just two shifts and an add.

Which is probably a better way to think about it.

> So clearly you don’t need to think about the details of escape analysis to understand what your code does

Right. To circle back to the context: Yeah, OP thought this was due to escape analysis, and that's why it worked. No, it's just a detail about why other code does something else. (but not really, because OP returned the slice by value)

So I suppose it's more correct to say that we were never discussing escape analysis at all. An escape analysis post would be talking about allocation counts and memory fragmentation, not "why does this work?".

Claude (per OPs post) led them astray.