On 29/09/2011 5:28 AM, Patrick Walton wrote:
On 9/28/11 9:17 PM, Graydon Hoare wrote:
- Expresses the "iteratee is aliased during iteration" fact to the
alias-checker, so you don't have to worry about invalidating
externalized iterators. This is important; particularly if you want
to exploit next part ...

I don't understand this, sorry... could you explain?

Sure. I want to make sure it's clear:

let v = [1,2,3,4];
let i = vec::iter(v);
v = [];
while (i.has_next()) {
    let e = i.next();
    foo(e); // crash.
}

Same thing happens if you mutate an element:

let v = [mutable [0],[1],[2],[3]];
let i = vec::iter(v);
let e = i.next();
v[0] = [];
e[0]++; // crash.

You're introducing either require-copy or unsafe-alias problems. Closure-passing style tells the alias-analysis system what it needs to keep reference-based iteration safe. You can't touch the vec while you're pointing into it. Statically. Even if you make copies, it's very likely nothing you return *from* the iterator can be a reference either since they'll be hidden state inside the iterator; the alias-analysis system can't make unsafe code safe.

We can't do this with exterior iters.

What about:
... (lambda holding unsafe pointers) ...

The version I wrote is actually safe (you can't crash it since the vec is kept alive during iteration); the one you wrote is contingent on the programmer "using it right". Alias-analysis problem, as above.

The complexity of loopctl is what I'm worried about, I guess. It
requires a bunch of dynamic "did this loop break? did this loop
early-return?" checks. I'm not sure what the precedent for this is.

Lots. Lots and lots. Many functional interfaces define a "return false from thunk to stop the enumerator" style. Early returns from non-total sequence enumerators in side-effecty functional languages have been around at least since common lisp:

http://www.lispworks.com/documentation/HyperSpec/Body/m_dolist.htm

Likewise it's in SRFI-44

http://srfi.schemers.org/srfi-44/srfi-44.html#enumprocs

Those less-side-effecty languages (haskell and ML say) always have a search-and-return-early "find" interface too:

http://www.haskell.org/ghc/docs/latest/html/libraries/base-4.4.0.0/Data-List.html#v:find

http://www.standardml.org/Basis/list.html#SIG:LIST.find:VAL

If you want to do the simpler thing, we don't need a "full" tri-state loopctl datatype, just bool. Do this:

    - Break in loop body => return false from loop thunk
    - Cont in loop body => return true from loop thunk
    - Ret in loop body => prohibited, but easy to emulate:

      let res = sentinel;
      let found = false;
      for e in iter(v) {
          if foo(e) {
              res = e;
              found = true;
              break;
          }
       }
       if found { ret res; }

Another possibility I'm totally fine with:

    - Eliminate 'for / break / cont' transformation altogether,
      just tell users to write in terminal-bool closure-passing style:

      let res = sentinel;
      let found = false;
      vec::each(v) {|e|
          if foo(e) {
              res = e;
              found = true;
              false
          } else {
              true
          }
       }
       if found { ret res; }

       lest you find this too chatty for the no-early-stop case, let
       me point out aspect B:

     - Write >1 iter interfaces on most collections, with varying
       strategies, to reduce unwanted boilerplate in cases you don't
       need it. Cold code is cold, harmless.

       vec::each(v)  ==  takes fn(e) -> (), returns ()
       vec::scan(v)  ==  takes fn(e) -> bool, returns ()
       vec::find(v)  ==  takes fn(e) -> bool, returns option::t<e>

I really, really think the exterior-iterator style is wrong. It puts logic in the wrong place, encourages hand-recoding loop logic incorrectly rather than collecting a rich library of correct enumerators. You can write a whole lot of cold enumerators that are safe and do-interesting-things to cover, I think, any of the needs of an external-iterator. This was less true when we had no closures, but now that we have block closures, I don't think there's any excuse.

If you don't believe me, believe Oleg!

http://okmij.org/ftp/papers/LL3-collections-enumerators.txt

-Graydon
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to