Execute an unnamed closure directly

I want to simplify the following code:

					let mut exec = move || {
						check_stderr(cmd.output()?)
					};
					tx.send(Event::Unblock(exec())).unwrap();

The reason for the use of the closure is the ? in cmd.output()?. Event::Unblock(...) contains a Result<()>, and I want to return the error inside the closure via the send channel instead of returning the error in the following function. This is because this is executed inside a thread::spawn to return the error asynchronously, since cmd.output() blocks for as long as the shell command runs. I would like to know if something like || {}.execute() is possible, or if I shouldn't use a closure at all for what I want to do.

It looks to me like you already know how to invoke the closure – you are doing exactly that with the postfix parentheses in the expression exec(). Of course, this works directly, too, so (|| {})() works just fine, even though it's pretty noisy.

However, I don't see a reason for a separate closure here. Your code is equivalent with cmd.output().and_then(check_stderr). You might need to include a .map_err(From::from) too, if the error types don't match up exactly.

6 Likes

Ignoring whether that's the best option in this particular instance, this is an interesting question.

Hypothetically, this can be done through the Fn* traits. The issue is that they are unstable and their api isn't very ergonomic -- we don't have variadic function definitions hence all parameters are taken as tuples.

In theory, your || {}.execute() would become (|| {}).call(()). This doesn't work on stable. This does work on nightly.

Is this worth it? Probably not!

1 Like

You mean like:

    (|| println!("Hi"))();

Works fine on stable.

1 Like

Thanks, and_then and map_err seem like the perfect fit for my use-case. The parameter to Event::Unblock is an anyhow::Result<()>, which is why the ? in the closure worked well. But now I have the problem you described, the errors don't match (I get expected struct anyhow::Error, found struct std::io::Error). Do you know how I can use map_err to fix this? Maybe anyhow provides something useful.

I probably don't know but can you show an example of the code you have?

Yeah of course, the code is in the execute method at watchbind/command.rs at main · fritzrehde/watchbind · GitHub

A simpler example? I have too much New Years cheer to be able to make heads or tails of that.

I already provided the necessary call in my previous post. You need to map From::from over the error type, as that's what ? also does.

1 Like