The problem is that iterators default to being **inline**. This means the 
compiler transforms the iterator into a block of code that is executed **only 
when it is in an iteration construct** like a for loop.

So in
    
    
    for file in walkDir(datapath / source / $instrument / "Prices"):
        paths.add(file.path)
        ...
    
    
    Run

This would actually be transformed into (I believe) something like this:
    
    
    ...
      when nimvm:
        for k, v in items(staticWalkDir(datapath / source / $instrument / 
"Prices", relative)):
          let file: tuple[kind: PathComponent, path: string]  = (k, v)
          
          paths.add(file.path)
          ...
      ...
    
    
    Run

So then the compiler isn't actually _calling_ anything per se, but detecting 
when an iterator is used in a for loop and then making the transformation 
_inline_.

When using the `{.closure.}` pragma, the compiler will make the iterator an 
actual function call (or something similar), making the iterator symbol a so 
called "first class citizen" that can be used how you are wanting to in your 
second example.

To get it to work in your first example, you can return a closure iterator from 
a pricestream proc like so:
    
    
    import os
    import algorithm
    
    type
      Instrument = object
        name: string
      Price = float
    
    proc `$`(ins: Instrument): string =
      ins.name
    
    var datapath = "."
    
    proc pricesFromCsv(path: string): seq[Price] =
      # Just hardcoded for example
      return @[1.0, 2.0, 3.0, 4.0, 5.0]
    
    proc pricestream*(source: string, instrument: Instrument): iterator(): 
Price =
      # When returning an iterator type, {.closure.} is inferred.
      return iterator(): Price =
        ## Iterator for all historic prices for the source, and instrument.
        var paths: seq[string]
        
        for file in walkDir(datapath / source / $instrument / "Prices"):
          paths.add(file.path)
        
        paths.sort(system.cmp[string])
        
        for path in paths:
          for price in pricesFromCsv(path):
            yield price
    
    
    var EUR_USD = Instrument(name: "EUR_USD")
    
    var stream = pricestream("oanda", EUR_USD)
    for p in stream(): # brackets are needed here to invoke the iterator
      echo p
    
    
    Run

Reply via email to