@@ -22,8 +22,8 @@ Rill has got you covered.
22
22
23
23
24
24
## 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.
27
27
28
28
There is a consensus in the Go community that functional programming style operations like Map, Filter, ForEach and others are
29
29
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
37
37
- For a multi-stage pipeline, everything must be manually managed at each stage, causing complexity to grow non-linearly
38
38
- Features like batching or ordered fan-in require even more complex orchestration and synchronization
39
39
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,
41
41
combining them into a more complex logic, can lead to code with lots of boilerplate that's difficult to write, read, and maintain.
42
42
43
43
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
46
46
47
47
48
48
49
-
50
49
## Example Usage
51
50
Consider an example application that loads users from an API concurrently,
52
51
updates their status to active and saves them back,
@@ -233,7 +232,7 @@ Rill provides several blocking functions out of the box:
233
232
[ Example] ( https://pkg.go.dev/github.com/destel/rill#example-ForEach )
234
233
- ** ToSlice:** Collects all stream items into a slice.
235
234
[ 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 .
237
236
[ Example] ( https://pkg.go.dev/github.com/destel/rill#example-ToSeq2 )
238
237
- ** Reduce:** Concurrently reduces the stream to a single value, using a user provided reducer function.
239
238
[ Example] ( https://pkg.go.dev/github.com/destel/rill#example-Reduce )
@@ -357,15 +356,30 @@ func main() {
357
356
}
358
357
```
359
358
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* .
363
369
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 )
367
371
368
372
``` 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
+
369
383
func genPositive (to int ) iter .Seq2 [int , error ] {
370
384
return func (yield func (i int , err error ) bool ) {
371
385
for i := 1 ; i <= to; i++ {
@@ -375,19 +389,6 @@ func genPositive(to int) iter.Seq2[int, error] {
375
389
}
376
390
}
377
391
}
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
- }
391
392
```
392
393
393
394
0 commit comments