r-lib / coro

Coroutines for R
https://coro.r-lib.org/
Other
156 stars 7 forks source link

Questions about yield differences between collect and loop/for #32

Closed mattwarkentin closed 3 years ago

mattwarkentin commented 3 years ago

Hi @lionel-,

I am just playing with coro and it was perhaps surprising to me that when looping over an iterator with loop() and for, that the yields from the iterator are different than if I call collect(). Is this behaviour expected? Am I misunderstanding/misusing these functions? Should iterators only ever return single-element objects?

collect() returns a list with an element for each column-value for a given row, while loop()/for return the expected value which is a single row of data.

library(R6)
library(coro)

Foo <- R6Class(
  classname = "Foo",
  public = list(
    data = mtcars,
    .length = function() {
      nrow(self$data)
    },
    .getitem = function(i) {
      self$data[i, ]
    }
  )
)

gen <- generator(
  function() {
    x <- Foo$new()
    for (i in 1:x$.length()) {
      yield(x$.getitem(i))
    }
  }
)

iter <- gen()

collect(iter, 1)
#> [[1]]
#> [1] 21
#> 
#> [[2]]
#> [1] 6
#> 
#> [[3]]
#> [1] 160
#> 
#> [[4]]
#> [1] 110
#> 
#> [[5]]
#> [1] 3.9
#> 
#> [[6]]
#> [1] 2.62
#> 
#> [[7]]
#> [1] 16.46
#> 
#> [[8]]
#> [1] 0
#> 
#> [[9]]
#> [1] 1
#> 
#> [[10]]
#> [1] 4
#> 
#> [[11]]
#> [1] 4

loop(for (i in iter) {
  print(i)
})
#>               mpg cyl disp  hp drat    wt  qsec vs am gear carb
#> Mazda RX4 Wag  21   6  160 110  3.9 2.875 17.02  0  1    4    4
#>             mpg cyl disp hp drat   wt  qsec vs am gear carb
#> Datsun 710 22.8   4  108 93 3.85 2.32 18.61  1  1    4    1
#>                 mpg cyl disp  hp drat    wt  qsec vs am gear carb
#> Hornet 4 Drive 21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
#>                    mpg cyl disp  hp drat   wt  qsec vs am gear carb
#> Hornet Sportabout 18.7   8  360 175 3.15 3.44 17.02  0  0    3    2
#>          mpg cyl disp  hp drat   wt  qsec vs am gear carb
# << TRUNCATED >>
lionel- commented 3 years ago

hmm it looks like a bug in collect(), I'll fix it thanks for reporting.

By the way, it seems you're missing a drop = FALSE here:

self$data[i, ]

If the data frame ends up having 1 column, subsetting rows without turning off drop will also unwrap the data frame.

x <- mtcars[1]
x[1:3, ]
#> [1] 21.0 21.0 22.8
mattwarkentin commented 3 years ago

Thanks for the reply. Yes, this example was hacky, just playing around with the new package.