Skip to content

Commit c35816e

Browse files
authored
Update Go 1.23 docs and readme (#34)
1 parent bb2b356 commit c35816e

File tree

4 files changed

+34
-34
lines changed

4 files changed

+34
-34
lines changed

README.md

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ Rill has got you covered.
2222

2323

2424
## Motivation
25-
Rill is not an iterator library or a functional programming library, though it may look like one.
26-
It's a concurrency library built specifically for Go channels.
25+
Rill might look like an iterator or functional programming library, but
26+
at its core it's a concurrency library made specifically for Go channels.
2727

2828
There is a consensus in the Go community that functional programming style operations like Map, Filter, ForEach and others are
2929
not idiomatic in Go, and that basic for-loops are better, faster, and more concise. This is true for slices,
@@ -37,7 +37,7 @@ but for channels, the complexity can quickly escalate beyond a basic for-loop as
3737
- For a multi-stage pipeline, everything must be manually managed at each stage, causing complexity to grow non-linearly
3838
- Features like batching or ordered fan-in require even more complex orchestration and synchronization
3939

40-
The list can be continued. And while tools like channels, ErrGroups or semaphores are powerful on their own,
40+
These increasing levels of complexity introduce several challenges. While tools like channels, ErrGroups or semaphores are powerful on their own,
4141
combining them into a more complex logic, can lead to code with lots of boilerplate that's difficult to write, read, and maintain.
4242

4343
Rill was born out of the desire to remove code duplication and to encapsulate all this complexity in a library with a
@@ -46,7 +46,6 @@ functional-style operations on channels, providing a natural way to achieve this
4646

4747

4848

49-
5049
## Example Usage
5150
Consider an example application that loads users from an API concurrently,
5251
updates their status to active and saves them back,
@@ -233,7 +232,7 @@ Rill provides several blocking functions out of the box:
233232
[Example](https://pkg.go.dev/github.com/destel/rill#example-ForEach)
234233
- **ToSlice:** Collects all stream items into a slice.
235234
[Example](https://pkg.go.dev/github.com/destel/rill#example-ToSlice)
236-
- **ToSeq2:**: Convert the stream items to a value-errors paris iterator.
235+
- **ToSeq2:** Converts a stream into an iterator of value-error pairs.
237236
[Example](https://pkg.go.dev/github.com/destel/rill#example-ToSeq2)
238237
- **Reduce:** Concurrently reduces the stream to a single value, using a user provided reducer function.
239238
[Example](https://pkg.go.dev/github.com/destel/rill#example-Reduce)
@@ -357,15 +356,30 @@ func main() {
357356
}
358357
```
359358

360-
## 1.23 iterator integration
361-
Starting from Golang 1.23, the language supports the "for-range" function. This
362-
allows users to directly use a for loop on an iterator in the iter package.
359+
## Go 1.23 Iterators
360+
Starting from Go 1.23, the language supports *range over function*, allowing users to define custom iterators
361+
for use in for-range loops. This feature enables Rill to integrate seamlessly with existing iterator-based functions
362+
in the standard library and third-party packages.
363+
364+
Rill provides **FromSeq** and **FromSeq2** functions to convert an iterator into
365+
a stream. Additionally, there's a **ToSeq2** function to convert a stream back into an iterator.
366+
367+
**ToSeq2** can be a good alternative to **ForEach** when concurrency is not needed.
368+
It gives more control and performs all necessary cleanup and draining, even if the loop is terminated early using *break* or *return*.
363369

364-
The Rill library supports using FromSeq2 or FromSeq to convert an iterator into
365-
a stream. It also supports using ToSeq2 to convert a stream into value-error
366-
pairs iterator.
370+
[Full runnable example](https://pkg.go.dev/github.com/destel/rill#example-ToSeq2)
367371

368372
```go
373+
func main() {
374+
nums := rill.FromSeq2(genPositive(40))
375+
squares := rill.Map(nums, 4, func(x int) (int, error) {
376+
return x * x, nil
377+
})
378+
for val, err := range rill.ToSeq2(squares) {
379+
fmt.Println(val, err)
380+
}
381+
}
382+
369383
func genPositive(to int) iter.Seq2[int, error] {
370384
return func(yield func(i int, err error) bool) {
371385
for i := 1; i <= to; i++ {
@@ -375,19 +389,6 @@ func genPositive(to int) iter.Seq2[int, error] {
375389
}
376390
}
377391
}
378-
379-
func main() {
380-
nums := rill.FromSeq2(genPositive(40))
381-
doubleNums := rill.Map(nums, 4, func(x int) (int, error) {
382-
return x * x, nil
383-
})
384-
for val, err := range rill.ToSeq2(doubleNums) {
385-
fmt.Println(val, err)
386-
// Just want to print the first result and discard the other values.
387-
// Don't worry about goroutine leak here. rill handle it for you.
388-
break
389-
}
390-
}
391392
```
392393

393394

example123_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
//go:build go1.23
2-
// +build go1.23
32

43
package rill_test
54

iter.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
//go:build go1.23
2-
// +build go1.23
32

43
package rill
54

65
import (
76
"iter"
87
)
98

10-
// FromSeq converts a iterator into a stream.
9+
// FromSeq converts an iterator into a stream.
1110
// If err is not nil function returns a stream with a single error.
1211
//
1312
// Such function signature allows concise wrapping of functions that return an
@@ -36,7 +35,7 @@ func FromSeq[A any](seq iter.Seq[A], err error) <-chan Try[A] {
3635
return out
3736
}
3837

39-
// FromSeq2 converts a value-error pairs sequence into a stream.
38+
// FromSeq2 converts an iterator of value-error pairs into a stream.
4039
func FromSeq2[A any](seq iter.Seq2[A, error]) <-chan Try[A] {
4140
if seq == nil {
4241
return nil
@@ -52,12 +51,14 @@ func FromSeq2[A any](seq iter.Seq2[A, error]) <-chan Try[A] {
5251
return out
5352
}
5453

55-
// ToSeq2 converts an input stream into a sequence of value-error paris.
54+
// ToSeq2 converts an input stream into an iterator of value-error pairs.
5655
//
57-
// This is a blocking ordered function that processes items sequentially. For
58-
// error handling, ToSeq2 is different from ToSlice; it does not simply return
59-
// the first encountered error. Instead, ToIterSeq will iterate all value-error
60-
// paris, allowing the client to decide when to stop.
56+
// This is a blocking ordered function that processes items sequentially.
57+
// It does not return on the first encountered error. Instead, it iterates over all value-error
58+
// pairs, either until the input stream is fully consumed or the loop is broken by the caller.
59+
// So all error handling, if needed, should be done inside the iterator (for-range loop body).
60+
//
61+
// See the package documentation for more information on blocking ordered functions.
6162
func ToSeq2[A any](in <-chan Try[A]) iter.Seq2[A, error] {
6263
return func(yield func(A, error) bool) {
6364
defer DrainNB(in)

iter_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
//go:build go1.23
2-
// +build go1.23
32

43
package rill
54

0 commit comments

Comments
 (0)