Go Weekly #2: Go 1.23 Iterators

Why People are Angry over Go 1.23 Iterators

  • Context:

    • Most languages provide standardized way to iterate over values stored in containers>).
  • Problem:

    • Go has for range for maps, slices, strings, arrays and channels but no generic mechanism for user-written containers.

    • Short list of some non-generic iterators:

      • runtime.CallersFrames: returns runtime.Frames iterates over stack frames; Frames has a Next method and a bool to check if there are more frames.

      • bufio.Scanner: iterates through an io.Reader; Scan method advances to the next value, Bytes method to return the value and Err to return error.

      • database/sql.Rows: iterates through the results of a query; also has Scan method.

    • Before Generics were introduced, no way to write an interface that described an iterator that would cover all of the use cases...

  • Solution:

    • Go 1.22 proposal of adding package iter can range over integers and functions:
    type (
      Seq[V any]     func(yield func(V) bool) bool
      Seq2[K, V any] func(yield func(K, V) bool) bool
    )
    

    (Seq2 represents a sequence of paired values: key-value, index-value or value-error)

    • An iterator is a function that passes successive elements of a sequence to a callback function yield, it returns true if it should continue, false if it should stop.
    type (
        Yield[V any] func(V bool)
        Yield2[K, V any] func(K,V) bool
    )
    
    • Examples:
    func Backward[E any](s []E) func(func(int, E) bool) {
        return func(yield func(int, E) bool) {
            for i := len(s)-1; i >= 0; i-- {
                if !yield(i, s[i]) {
                    // Where clean-up code goes
                    return
                }
            }
        }
    }
    
    s := []string{"a", "b", "c"}
    for _, el in range Backward(s) {
      fmt.Print(el, " ")
    }
    // c b a
    
  • Conclusion:

    • The for range is getting complex:
      • return true => continue
      • return false => break
    • Feels too functional than an imperative language
    • Still the purpose is good, let's wait to see the adoption in community after awhile

sticker #1
Subscribe to Dwarves Memo

Receive the latest updates directly to your inbox.