First of all, I realize that this might go somewhat against the grain of Nim. 
And also it's not how I normally write code in Nim. I will start by explaining 
very briefly what I am doing and what's my motivation but feel free to skip to 
the last code example and the actual question following it. I'm currently 
experimenting with closures. I know that I can capture the reference to an 
object or an attributes of an object like so:
    
    
    type
      Book = ref object
        title: string
    
    var moby = Book(title: "Moby Dick")
    
    let getTitle = proc(): string = moby.title
    echo getTitle()
    
    
    Run

What I find interesting is that `getTitle` does not directly depend on the 
`Book` type. And also when I change the title of the book itself (i.e. `moby`) 
the `getTitle` function will return the correct (current) title. I can likewise 
implement a setter that can manipulate an attribute without an explicit 
reference to the type:
    
    
    let setTitle = proc(newTitle: string) = moby.title = newTitle
    
    
    Run

Additionally, I can define these anonymous functions for (single, concrete) 
objects of different types (say `Movie` and `Book`) and then have a homogeneous 
access, meaning I can put multiple `getTitle` closures into a sequence 
`seq[proc(): string]`, even if they act on different types of objects.

I'm currently using this approach in an experimental tweening library. I think 
tweening really is a cross-cutting concern and I want to keep the coupling to 
the objects being tweened very minimal.

Sidenote: This looks somewhat similar to implementing `getTitle[T](obj: T): 
string` but I can't have a `seq[T]`. I also thought about tagged unions but as 
far as I know these can't be easily extended.

Now on to my question. I tried this with a list of books and a for loop:
    
    
    type
      Book = ref object
        title: string
    
    var
      books = @[
        Book(title: "War and Peace"),
        Book(title: "Of Mice and Men"),
        Book(title: "Moby Dick")
      ]
      
      titleReaders: seq[proc(): string]
    
    for i in 0..2:
      let w = proc(): string = books[i].title
      echo "Getter called inside loop: ", w()
      titleReaders.add(w)
    
    for tr in titleReaders:
      echo "Getter called outside loop: ", tr()
    
    
    Run

Link: <https://play.nim-lang.org/#ix=3zRL>

Here the closure inside the for loop also captures the loop variable `i` which 
equals 2 once the loop has finished. So all my title getters return "Moby 
Dick". (And it's also the same with a `for b in books` type of loop.)

Is there a way to capture "the book itself" inside the loop, basically 
resolving one level of reference? I thought maybe with `addr` or `[]` but I 
couldn't get it to work. (I guess I could also write an alternative loop as a 
macro that expands into separate statements but I would rather stick to 
built-in loop constructs.)

Reply via email to