I have this which I have faith is close to working as desired. What I am trying to do is range over a sequence, but be able to call the next item yourself and asynchronously
sync:
for r := range even.Sequence() { if !r.Done { r.Contnue() } }
or async:
for r := range even.Sequence() { go func(){ if !r.Done { r.Contnue() } }() }
here is the full code in main:
package main import "fmt" type HasNext[T any] interface { Next() (bool, T) } type Nexter[T int] struct { Val int End int } type Ret struct { Done bool Value int Contnue func() } func (n *Nexter[int]) Sequence() chan Ret { var c = make(chan Ret) even := newEven() var x func() x = func() { fmt.Println("got here 3") <-c fmt.Println("got here 4") fmt.Println("got here 5") var b, v = even.Next() c <- Ret{b, v, x} if b { close(c) } } go func() { var b, v = even.Next() fmt.Println("got here 1") c <- Ret{b, v, x} fmt.Println("got here 2") }() return c } func (n *Nexter[int]) Next() (bool, int) { n.Val = n.Val + 1 if n.Val > n.End { return true, int(n.Val) } return false, int(n.Val) } func newEven() *Nexter[int] { n := 0 return &Nexter[int]{n, 5} } func main() { even := newEven() for r := range even.Sequence() { fmt.Println("value:", r.Value) if !r.Done { fmt.Println("continuing...") r.Contnue() } } }
but currently I get this output:
```golang got here 1 got here 2 value: 1 continuing… got here 3 fatal error: all goroutines are asleep - deadlock! goroutine 1 [chan receive]: main.main() /Users/me/codes/vibeirl/wss/test/iterator/main.go:83 +0x66 ```
```golang got here 1 got here 2 value: 1 continuing… got here 3 fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]: main.main() /Users/me/codes/vibeirl/wss/test/iterator/main.go:83 +0x66 ```
so clearly it’s deadlocking somewhere but not sure where/how exactly
The issue you’re encountering is related to the channel communication and synchronization in your Sequence method. The deadlock occurs because you’re trying to receive from the channel (<-c) before any other goroutine has a chance to send data to it. The goroutine that sends data (go func() {...}) is blocked until someone reads from the channel.
Sequence
<-c
go func() {...}
To fix this, you need to ensure that you have separate goroutines for sending and receiving data. Here’s an updated version of your Sequence method:
func (n *Nexter[int]) Sequence() chan Ret { c := make(chan Ret) go func() { var b, v = n.Next() fmt.Println("got here 1") c <- Ret{b, v, nil} // Initial send fmt.Println("got here 2") for { r := <-c fmt.Println("got here 3") if r.Done { close(c) return } go func() { var b, v = n.Next() c <- Ret{b, v, nil} // Send the next value fmt.Println("got here 4") }() } }() return c }
In this version, I removed the x function and modified the loop in the goroutine to handle both initial and subsequent sends. The initial send is performed before entering the loop, and subsequent sends are performed in a new goroutine. This should prevent the deadlock issue you were facing.
x
However, keep in mind that using a channel in this way may not be the most idiomatic Go code. Channels are typically used for communication between goroutines, and the structure of your Sequence method might be better suited for a more straightforward loop without the need for a channel. If your intention is to iterate over a sequence asynchronously, you might consider using goroutines and a sync.WaitGroup for better synchronization.
sync.WaitGroup