This sounds fine. The only downside I can see to Marijn's technique is
that there is no way for an iteration function to distinguish "broke out
of the loop" from "returned out of the loop". This may or may not be
important? I could imagine that the iterator may want to perform
actions on a break which conceptually follow the loop but not perform
those actions on a return, but I can't actually come up with any
convincing examples.
As far as nesting, I think you can do it in various ways, but as long as
we're going to build for loops into the language it makes sense to do
nesting the more efficient way that you describe: that is, the outer for
loop creates a location to store to and inner for loops all refer to
that same location.
Just for reference, though, the naive translation of a nested loop pair
works fine as long as you translate ret consistently---outside of a for
loop, it returns from the method, inside it stores to the innermost temp
and breaks. In that case, the inner for loop expands in the first round to:
for i in a {
let tmp2 = none;
b.iter { |j| tmp2 = some(...); ret false; } // <-- this is a
"native" return
if tmp2 != none {
ret option::unwrap(tmp2); // <-- this return must still be
desugared
}
}
now when we de-sugar the outer loop we get:
let tmp = none;
a.iter { |i|
let tmp2 = none;
b.iter { |j| tmp2 = some(...); ret false; } // <-- this is a
"native" return
if tmp2 != none {
tmp = some(option::unwrap(tmp2));
ret false; // <-- this is a "native" return
}
}
if tmp != none {
ret option::unwrap(tmp); // <-- this is a native return
// as there are no more for loops
}
Of course, here you end up with two temporaries where only one is needed
so it makes more sense to be smart about it. But it's good to know that
the translation does compose: I'd be worried otherwise.
Niko
On 2/29/12 2:01 PM, Graydon Hoare wrote:
On 12-02-29 01:12 PM, Marijn Haverbeke wrote:
I was actually thinking there wouldn't have to be a special may_return
type at all. The returned value can be an option, and return can store
to that and then break. Code after the call to the iterator then
checks for a `some` value in the return slot and, if found, returns
it.
This is coming into focus a little better. I like where it's going. If
we make these two assumptions though:
- Repurpose the 'for' loop to avoid boilerplate
- Store-into-option to avoid a polymorphic tag
Can we not, again, just get away with 'bool'? That is:
for i in v(z) { ret q; }
becomes:
{
let tmp = none;
v.iter(z) {|i| tmp = some(q); ret false; }
alt tmp {
some(q) { ret q; }
_ { }
}
}
and the iter can be written pleasantly as:
fn iter(self: [int], x: foo, f: fn(int) -> bool) {
let i = 0;
while f(i) { i += 1; }
}
Two questions: is this tolerable, and does it nest properly?
I think it's tolerable, personally. I'd appreciate hearing other
opinions on that.
Meanwhile let's look at nesting...
for i in a {
for j in b {
ret q;
}
}
does not work if the nesting translates, naively, that is, if it becomes:
let tmp1 = none;
a.iter() {|i|
let tmp2 = none;
b.iter() {|j|
tmp2 = some(q); ret false;
}
alt tmp2 {
some(q) { ret q; }
_ {}
}
}
alt tmp {
some(q) { ret q; }
_ {}
}
This is a bad translation -- won't even compile -- since the inner
block winds up with the wrong type. And anyways control flow doesn't
propagate right. I think there's a right translation though. If it
instead becomes:
let tmp = none;
a.iter() {|i|
b.iter() {|J|
tmp = some(q); ret false;
}
if tmp != none { ret false; }
}
alt tmp {
some(q) { ret q; }
_ {}
}
Then I think it's ok. IOW there's subtlety to the translation, it has
to be nesting aware. In particular:
- There's only _one_, outermost option to write to. All early rets
write to it.
- Any nested for loop has to inspect the outer option at its end,
and ret false to break its enclosing loop, if the option changed to
'some'.
I _think_ that's enough to make the translation work. Anyone see
holes in it? I'm definitely interested in "getting this right", it's
just somewhat ... subtle.
-Graydon
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev