Question

Note that this question pertains to a version of Rust before 1.0 was released

Do I understand correctly that it is now impossible to return a closure from a function, unless it was provided to the function in its arguments? It is very useful approach, for example, when I need the same block of code, parameterized differently, in different parts of program. Currently the compiler does not allow something like this, naturally:

fn make_adder(i: int) -> |int| -> int {
    |j| i + j
}

The closure is allocated on the stack and is freed upon returning from a function, so it is impossible to return it.

Will it be possible to make this work in future? I heard that dynamically-sized types would allow this.

Was it helpful?

Solution

This can't ever work for a stack closure; it needs to either have no environment or own its environment. The DST proposals do include the possibility of reintroducing a closure type with an owned environment (~Fn), which would satisfy your need, but it is not clear yet whether that will happen or not.

In practice, there are other ways of doing this. For example, you might do this:

pub struct Adder {
    n: int,
}

impl Add<int, int> for Adder {
    #[inline]
    fn add(&self, rhs: &int) -> int {
        self.n + *rhs
    }
}

fn make_adder(i: int) -> Adder {
    Adder {
        n: int,
    }
}

Then, instead of make_adder(3)(4) == 7, it would be make_adder(3) + 4 == 7, or make_adder(3).add(&4) == 7. (That it is Add<int, int> that it is implementing rather than just an impl Adder { fn add(&self, other: int) -> int { self.n + other } is merely to allow you the convenience of the + operator.)

This is a fairly silly example, as the Adder might just as well be an int in all probability, but it has its possibilities.

Let us say that you want to return a counter; you might wish to have it as a function which returns (0, func), the latter element being a function which will return (1, func), &c. But this can be better modelled with an iterator:

use std::num::{Zero, One};

struct Counter<T> {
    value: T,
}

impl<T: Add<T, T> + Zero + One + Clone> Counter<T> {
    fn new() -> Counter<T> {
        Counter { value: Zero::zero() }
    }
}

impl<T: Add<T, T> + Zero + One + Clone> Iterator<T> for Counter<T> {
    #[inline]
    fn next(&mut self) -> Option<T> {
        let mut value = self.value.clone();
        self.value += One::one();
        Some(value)
    }

    // Optional, just for a modicum of efficiency in some places
    #[inline]
    fn size_hint(&self) -> (uint, Option<uint>) {
        (uint::max_value, None)
    }
}

Again, you see the notion of having an object upon which you call a method to mutate its state and return the desired value, rather than creating a new callable. And that's how it is: for the moment, where you might like to be able to call object(), you need to call object.method(). I'm sure you can live with that minor inconvenience that exists just at present.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top