&mut before a closure meaning?

Hi,
I am reading the Rust's github repo to learn some idoms because I think it's the best resource out there to familiarize/learn them in production code.

But even reading the doc about closure and mutability, I am not quite sure of the meaning of this line
https://github.com/rust-lang/rust/blob/master/library/std/src/net/tcp/tests.rs#L870

each_ip(&mut |addr| {...})

My take: we have a closure doing something, passed as a mutable element to

fn each_ip(f: &mut dyn FnMut(SocketAddr)) {...}

which expects a mutable function (here a closure) that will be dynamically dispatched depending on what it is. Also, this callback has its state mutable. A kind of callback in other languages.

Am I right?

Maybe I got it wrong, please do not hesitate to correct my understanding

Yeah, that's about right. The |addr| {...} part is a closure, and then they create a mutable reference to the closure and pass that.

Knowledge is coming :call_me_hand: :call_me_hand:

Thanks Alice

Note that most code would use

fn each_ip<F: FnMut(SocketAddr)>(f: F) {

which is different in two ways: each_ip is generic over the function rather than using dynamic dispatch, and it takes the function by value instead of by reference.

The probable reason it is written the way it is instead is to minimize compile time of the tests; generic functions have to be compiled over again for each specific type they are used with, which can allow optimizations for the specific case, but here is not worth doing since test code only ever runs once.

And then the &mut is because dyn types must be passed by reference (or Box or other pointer type), not because it is needed for functions or provides any benefit itself.

2 Likes

That is indeed a must simpler signature, the one I would go with.

Maybe I should discard the tests part and focus on the core implementations to avoid such code (I mean the not so idomatic one)?

Actually, it is good that you now know that both options exist. &dyn and &mut dyn are lesser used but I might even say they are less used than they should be. The main thing I wanted you to notice by comparing them is that dyn is not required here.

(Oh, and another case where &mut <some function type> comes up is recursive functions that take an FnMut callback. You'll find that for the borrow checker and type checker to be happy, the only way to write them is passing the callback as &mut, whether dyn or not.)

Don't &dyn and &mut dyn incur a runtime penalty though?

Yes, they do, but they reduce instructions cache pressure which means that if you use dynamic dispatch for the code which is rarely used you make the code which used often faster.

Interesting point, I will keep that in mind :+1:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.