Could lambdas have explicit self parameter?

Allow recursive lambdas with the following syntax: let lambda = |&self, i| {self(i - 1);};

Similar feature has been discussed to be added to C++ with the following syntax: Deducing this

I have no idea whether this is acceptable or even possible to do in Rust, just my suggestion as I have not seen any open issues about this idea.

1 Like

self is a keyword, so it seems possible, at least.

One nice bonus would that that it would be very clear which trait it'll implement, since if you write self it's FnOnce, etc.

Is this possible given that closures have to implement FnOnce?

Recursive lambda with captured state is a self-referential struct. You can use fn syntax if it doesn't capture.

1 Like

Previous discussion

1 Like

You can just delegate to the implementation of Fn (assuming you require the closure to be able to implement it).

You don't need to reference the closure in itself, creating a self-referential struct. You just need to "expose" the self parameter of its call method.

This syntax would make it difficult for a lambda defined within a method to reference the self from the method, since the self of the lambda would shadow the self of the method.

6 Likes

Playing devil's advocate here: what is the use case? I have often written lambdas as well as recursive functions. I don't remember ever wanting a recursive lambda though.

The example in OP should really be a standalone function, it doesn't capture anything.

That said I don't mind the functionality, I just don't see where I would be invaluable (or even useful).

At some point code is cleaner when not using lambdas. I don't know where that border is, but a function being recursive might be a good indication that it is perhaps complex enough to be factored out into a standalone function.

5 Likes

I've haven't run into it in rust, but in javascript I've occasionally had to refer to lambads themselves (by the variable to which they're assigned) to pass them forward at the end. E.g. a scheduled task that resubmits itself.

2 Likes

If you want a recursive function that captures state, you'd have to define a new type rather than a function, and you can't currently implement the Fn family of traits by hand in stable Rust. I'm not sure that's a compelling argument.

On this part, you can write something like this:

fn get_factorial_func() -> impl FnMut(u32) -> u32 {
  struct Fac { /* Add captures here */ }
  impl Fac {
    fn calc(&mut self, n: u32) -> u32 {
      if n == 0 {
        return 1;  
      }
      n * self.calc(n - 1)
    }
   }
   let mut f = Fac {};
   move |x| f.calc(x)
}

Playground

2 Likes

More features is not necessarily better. Lambdas are not part of an impl, to me it will only be confusing. And which self type will be used there?

In Rust self from outer lexical scope can also be captured? How to distinguish them then?

I don't see how this is replying specifically to anything I have said. I am not the one who proposed using the self syntax. I only answered the question about potential uses.

If a lambda refers to itself as self it will shadow self that is visible outside.

1 Like

Yes, and even if we had something like self fn as a keyword, it would again shadow self in cases of a recursive lambda within a recursive lambda. If this issue were to be solved in Rust, I think we would either need a named self parameter (like in the C++ proposal). Or change the rules regarding visibility of the varable in a let statement, which would be a breaking change, since current code works with the assumption that identifiers can not refer to the name being currently defined.

It could do so through other ways then self. I.e. the general ability for a closure to refer to itself does not have to be tied to the keyword or shadowing. And even if it were shadowing could be solved by some way of disambiguation.

But again, I only answered the question about use-cases...

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.