Hello,

I have a conceptual/style question here.

In C++ (and presumably some other languages), there is a concept called 
"iterator invalidation". The basic idea is that while iterating a structure, 
changes to the structure could break iteration, leading to a loss of memory 
safety. It is also undefined behavior to use an "old" iterator, or one that was 
created before the structure was updated.

A while ago I switched my former C++ projects to Rust and found that the 
language's borrowing rules protect against this error: 
    
    
    // In stdlib, oversimplified, generics removed for simplicity:
    mod vec {
        struct Vec {
        }
        
        struct Iter<'a> {
            vector: &'a Vec,
            //...
        }
        
        impl Iterator for Iter {
            //...
        }
        
        impl Vec {
            pub fn iter<'a>(&'a self) -> Iter<'a> {
                Iter {
                    vector: self,
                }
            }
        }
    }
    
    // Test
    let mut v = vec![1, 2, 3];
    for i in &v {
        if *i == 2 {
            v.clear(); // Yay, compile time error, no unsafety.
        }
    }
    

So, in Nim, it is possible to modify a structure you are iterating. For some 
simple structures, though, this works fine. For example, the following does not 
crash. 
    
    
    var s = @[1, 2, 3]
    for i in s:
      echo s
      if i == 2:
        s.setLen(0) # iteration stops, no unsafety.
    

However, this seems fairly delicate - the iterator must be implemented in a way 
that expects the seq to be modified. Perhaps incidentally, this is true.

So my question is:

  * Should I/can I ever count on an `iterator` in Nim to handle the structure 
being changed during iteration?
  * Is there any way to leverage Nim's type system or metaprogramming 
capabilities to create an `iterator` that forbids modifying the structure?


Reply via email to