On Sep 11, 2012, at 7:48 PM, Jason Orendorff wrote:

> I'd appreciate a less contrived motivating example.  The best way to
> implement this dataSnapshot() function is simply:
> 
>    function dataSnapshot(aCollection) {
>        return aCollection.clone();
>    }
> 
> -j
> 


My original example was something like:

function *dataSnapshot(aDataSource) {
  let snapshot = aDataSource.captureCurrentState();
  for (let i=0; i<snapshot.length; i++) yield snapshot[i]
}

It wasn't actually quite as  intentionally clear as the above and that allowed 
it to evolve within the thread into something that could arguably be restated 
as you show. But that was why I created the original example.

The intent of the original was to show a situation where:

there is a dynamically changing data source you want to analyze
You need to capture it for the analysis while it is in a stable state
The data capture process does not produce a "clone" but a different (perhaps 
more efficient for readonly access)
You know how to navigate this captured data structure and want to provide a 
generator-based iteration that a analysis process can you to access its elements
You need to be sure that the data is captured when at the exact point in 
program where "dataSnapshot" was invoked, not at some arbietrary later time 
when "next" is first called.

I think these requirements are pretty typical of a common situation that occurs 
 when you want to perform stable traversal over dynamically mutable object 
structures and the example was contrived to show some pitfalls that could occur 
if you try to do this using a generator.

The original example fails for at least the last bullet.  To fix that, it would 
have to be rewritten, something like:

function dataSnapshot(aDataSource) {
  let snapshot = aDataSource.captureCurrentState();
  return  function *() {
     for (let i=0; i<snapshot.length; i++) yield snapshot[i]
   }
}

Note that this rewrite eliminates the need for an formal parameters on the 
actual generator definition.

If dataSnapshot was a method on some object and the iteration results depended 
upon that object, you might have instead originally coded it as:

class DataSourceAnalyzer {
    ...  //a constructor and other methods
   *dataSnapshot(aDataSource) {
      let snapshot = aDataSource.captureCurrentState();
      for (let i=0; i<snapshot.length; i++) yield 
this.analyzeElement(snapshot[i]);  //  <--- note use of this
  }
}

This also falls the last requirement in the bullet list above.  So, you might 
refactor similarly to what I did for the non-method form:

class DataSourceAnalyzer {
    ...  //a constructor and other methods
   dataSnapshot(aDataSource) {
      let snapshot = aDataSource.captureCurrentState();
      return  function *() {
         for (let i=0; i<snapshot.length; i++) yield 
this.analyzeElement(snapshot[i]);  //  <--- note erroneous use of this
      }
  }
}

and forget that the function * expression uses a dynamic this.  If you 
remembered that you would instead have had to revert to ES<6 style this capture:

class DataSourceAnalyzer {
    ...  //a constructor and other methods
   dataSnapshot(aDataSource) {
      let snapshot = aDataSource.captureCurrentState();
      let self = this;
      return  function *() {
         for (let i=0; i<snapshot.length; i++) yield 
self.analyzeElement(snapshot[i]);  //  <--- note use of self instead of this
      }
  }
}

Using my alternative generator syntax, this would be written as:

class DataSourceAnalyzer {
    ...  //a constructor and other methods
   dataSnapshot(aDataSource) {
      let snapshot = aDataSource.captureCurrentState();
      return  *=> for (let i=0; i<snapshot.length; i++) yield 
this(snapshot[i]);  //  <--- note valid of lexical this
  }
}






_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to