Sorry for the late reply and thank you all for your replies.
I think I should loosen the requirements for my question without 
introducing the concept of ownership. 

Does setting c to nil in "move" function helps GC sweep the connection 
object pointed by c and c2 soon if G1 keeps long but does not use 
connection object, G2 finishes soon and the c pointer does not exist in 
temporary locations, slots that can hold pointers, or registers? The 
program in original post 
<https://groups.google.com/g/golang-nuts/c/vNoKW_3joS8> in pasted here:

```go
func move[T any, PT *T](pp *PT) (res PT) {
res = *pp
*pp = nil
return
}

// Goroutine G1
c, err := getFtpConnection()
if err != nil {
return nil, err
}
go func(c2 *ftp.ServerConn) { // Goroutine G2
c2.List()
}(move(&c))
// c will not be used later
```

I may do an experiment with goref <https://github.com/cloudwego/goref/> 
tool, which I recently found, and show the result here. Thanks. 
On Wednesday, January 7, 2026 at 8:41:56 PM UTC+8 Andrey Andrade wrote:

>  The short answer is no, this won't work reliably, for several reasons:
>
>   1. Race between move and goroutine creation
>
>   go func(c2 *ftp.ServerConn) {
>       c2.List()
>   }(move(&c))
>
>   The sequence is:
>   1. move(&c) executes in G1
>   2. Return value sits in G1's registers/stack
>   3. New goroutine G2 is scheduled
>   4. Value is copied to G2's stack
>
>   Between steps 1-4, the pointer lives in G1's execution context. The GC 
> could run during this window.
>
>   2. Compiler doesn't understand ownership
>
>   c, err := getFtpConnection()
>   // Compiler may keep 'c' in a register here
>   go func(c2 *ftp.ServerConn) {
>       c2.List()
>   }(move(&c))
>   // Even with c = nil, compiler might have copies
>
>   Go's compiler can:
>   - Keep copies in registers
>   - Introduce temporaries you don't see
>   - Reorder operations
>
>   Setting c = nil in source doesn't guarantee all machine-level references 
> are cleared.
>
>   3. GC scans conservatively
>
>   Go's GC scans entire stack frames, including:
>   - All slots that could hold pointers
>   - Registers at safepoints
>   - Temporary locations
>
>   There's no mechanism to tell the GC "I've semantically transferred this 
> pointer."
>
>   4. The move generic doesn't compile
>
>   func move[PT *any](pp *PT) (res PT) // Won't work
>
>   You'd need:
>   func move[T any, PT *T](pp *PT) PT
>
>   But even then, it doesn't achieve the semantic goal.
>
>   5. What would actually be needed
>
>   For true ownership transfer, you'd need runtime support:
>
>   // Hypothetical - doesn't exist
>   func runtime.TransferOwnership[T any](from *T) T {
>       // 1. Atomically mark object as "in transfer"
>       // 2. Clear stack slot with write barrier
>       // 3. Return value with new ownership metadata
>   }
>
>   This would require changes to:
>   - GC's stack scanner (recognize transferred objects)
>   - Write barriers (track ownership changes)
>   - Escape analysis (understand cross-goroutine transfers)
>
>   The fundamental issue
>
>   Go's memory model is shared memory with GC, not ownership-based. The GC 
> assumes any reachable pointer might be used. There's no concept of "this 
> goroutine owns this object."
>
>   Rust can do this because ownership is compile-time — the borrow checker 
> ensures single ownership. Go would need either:
>   1. Compile-time ownership tracking (major language change)
>   2. Runtime ownership metadata (significant GC overhead)
>
>   What you can do instead
>
>   // Use channels for explicit handoff
>   ch := make(chan *ftp.ServerConn, 1)
>   c, err := getFtpConnection()
>   if err != nil {
>       return nil, err
>   }
>   ch <- c
>   c = nil // Now truly unreachable from G1
>   go func() {
>       c2 := <-ch
>       c2.List()
>   }()
>
>   This achieves a cleaner ownership transfer, though the GC still manages 
> the lifetime — it just now knows c in G1 is nil before G2 runs.
>
> Em quarta-feira, 7 de janeiro de 2026 às 04:15:20 UTC-3, Axel Wagner 
> escreveu:
>
>> I'm not sure your `move` function actually does anything in this case. 
>> AIUI the compiler and runtime are already clever enough to recognize that c 
>> is no longer used after the `go` statement (hence the necessity of 
>> runtime.KeepAlive) and that's all your `move` is trying to do, no?
>> And in the general case, you have no guarantee that a pointer passed to 
>> `move` is the *only* pointer to the relevant object.
>> So ISTM the cases where the Go implementation *can't* tell that c is no 
>> longer used, adding the `move` doesn't really help.
>>
>> Do you have concrete evidence that this helps in some cases? Because 
>> otherwise it seems like a premature optimization that mostly makes the code 
>> harder to read.
>>
>> On Wed, 7 Jan 2026 at 04:25, Qingwei Li <[email protected]> wrote:
>>
>>> Take the following program as an example.
>>>
>>> ```go
>>> c, err := getFtpConnection()
>>> if err != nil {
>>> return nil, err
>>> }
>>> go func(c2 *ftp.ServerConn) {
>>> c2.List()
>>> }(c)
>>> // c will not be used later
>>> ```
>>>
>>> Let's add the `move` function.
>>>
>>> ```go
>>> // pointer is 
>>> func move[PT *any](pp *PT) (res PT) {
>>> res = *pp
>>> *pp = nil
>>> return
>>> }
>>> ```
>>>
>>> ```go
>>> // Goroutine G1
>>> c, err := getFtpConnection()
>>> if err != nil {
>>> return nil, err
>>> }
>>> go func(c2 *ftp.ServerConn) { // Goroutine G2
>>> c2.List()
>>> }(move(&c))
>>> // c will not be used later
>>> ```
>>>
>>> Would this `move` without runtime support make GC unable to reach the 
>>> object pointed by `c` scanning from the stack of goroutine G1 so that the 
>>> ownership of object is entirely moved to goroutine G2? With this ownership 
>>> transfering, freegc for `c2` in the end of goroutine G2 is feasible in 
>>> cross-goroutine reference case.
>>>
>>>
>>> -- 
>>> You received this message because you are subscribed to the Google 
>>> Groups "golang-nuts" group.
>>> To unsubscribe from this group and stop receiving emails from it, send 
>>> an email to [email protected].
>>> To view this discussion visit 
>>> https://groups.google.com/d/msgid/golang-nuts/5c0b8aaf-8470-4de2-91f6-5d74e884dff3n%40googlegroups.com
>>>  
>>> <https://groups.google.com/d/msgid/golang-nuts/5c0b8aaf-8470-4de2-91f6-5d74e884dff3n%40googlegroups.com?utm_medium=email&utm_source=footer>
>>> .
>>>
>>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/golang-nuts/8cb49d04-fece-4805-b2aa-fe4dd1546378n%40googlegroups.com.

Reply via email to