I have code which (greatly simplified) boiled down to:

```
fn attempt_1<T>(action: &fn() -> T) -> T {
    action()
}

fn call_attempt_1() -> ~str {
    let mut index = 0;
    let string = ~"str";
    do attempt_1 {
        // No problem here. We have a stack closure.
        index += 1;
        // Error: cannot move out of captured outer variable
        // Makes sense. Compiler can't tell the action will only be invoked
        // once.
        string
    }
}
```

So, I heard there are things called `once fn`, which seem to be what I
need. Even though the compiler warned me away from them, I thought I'd give
them a try in the spirit of investigation:

```
fn attempt_2<T>(action: &once fn() -> T) -> T {
    action()
}

fn call_attempt_2() -> ~str {
    let mut index = 0;
    let string = ~"str";
    do attempt_2 {
        // Error: cannot assign to immutable captured outer variable in a
heap closure
        // It seems that `&once fn` is a _heap_ closure? Makes no sense...
It
        // would have made sense if it was an `~once fn`, but there's no way
        // that `action_2` should be able to store somewhere a reference to
an
        // `&once fn`, so a stack closure should be fine!
        index += 1;
        string
    }
}
```

So, obviously `once fn` doesn't do what I expected it to do, which is to
simply assert "this fn is only called once". It seems it does that but also
carries some extra baggage of also saying "force me to be a heap closure".
It isn't clear to me _why_ these two should be conflated - after all, one
could just say `~once fn` if one wanted a heap closure. Can someone
enlighten me on this?

At any rate, I then resorted to:

```
fn attempt_2<T>(action: &fn() -> T) -> T {
    action()
}

fn call_attempt_2() -> ~str {
    let mut index = 0;
    let string = ~"str";
    let string_cell = Cell::new(string);
    do attempt_1 {
        // No problem here. We have a stack closure.
        index += 1;
        // Dynamic assertion that the action is only invoked once. Costs in
        // both extra ugly source code lines and in run-time overhead.
        string_cell.take()
    }
}
```

So, this works, but boy is it ugly, not to mention inefficient Can someone
suggest a better way to achieve this, and shed some light on the status of
the `once fn` construct in general?

Thanks,

Oren Ben-Kiki
_______________________________________________
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to