First impressions of Go 1.23's range-over-func feature

July 18, 2024

I’m taking a detour from the Go spec today, to share my experience with the new range-over-func feature coming in Go 1.23:


Exactly a year ago (yesterday), Russ Cox submitted a proposal to add two new range capabilities to Go: range-over-int, and range-over-func. The former was added to Go 1.22. And the latter left me immediately skeptical. I spent a fair amount of time (as measured in Internet minutes) trying to understand the proposal, and eventually coming to the conslusion that I wasn’t very smart.

Assumptions

In the year since then, my co-host, Shay Nehmad, and I have talked about the range-over-func progress several times on the Cup o’ Go podcast, sharing some resources from the community, as well as our own speculation. And that’s probably a good place to start this post: My own speculations about this feature.

  • Ugly interface names First, the interface names annoyed me. If you’re patient enough to actually read through the issue, you’ll come to this comment, which has this tidbit burried deep inside:

    package iter
    
    type Seq0 func(yield func() bool) bool
    type Seq[V any] func(yield func(V) bool) bool
    type Seq2[K, V any] func(yield func(K, V) bool) bool
    

    Yuck! One thing Shay and I could agree on was how terrible these names were. It reminded me of Perl’s confusingly named open2 and open3, which always required looking up the documentation to either write or read the code that used them. I was afraid these silly names would lead to the same problem when writing Go iterators.

  • Steep learning curve Second, considering the effort it took to understand the range-over-func proposal, it seemed that this feature would prove to be cumbersome to use when writing an iterator. But the consensus seemed to be that it would be worth the effort, becasue it would be easier to use the iterators. That seemed like a reasonable enough trade off. I’d be willing to do the heavy lifting to make life easier on the consumers of my APIs. At least in some cases.

  • New keyword Closely related to the general learning curve, the new yield keyword* was a bit confusing and magical to me. But I’m a big boy. If I can learn to knit and crochet (and yes, I can do both), surely I can learn to use yield in Go!

    *Spoiler alert: not a keyword, after all.

  • Backward compatibility Putting new iterators behind //go:build v1.23 tags could be annoying, and render different effective versions of a library, depending on which version of Go the consumer is using.

So that was my starting point. These were my key beliefs and assumptions about range-over-func as of 24 hours ago.

« Keep reading… »


Share this

Direct to your inbox, daily. I respect your privacy .

Unsure? Browse the archive .

Get daily content like this in your inbox!

Subscribe