At the bottom of http://gtk-rs.org/tuto/closures, they gave us this
macro_rules! clone {
(@param _) => ( _ );
(@param $x:ident) => ( $x );
($($n:ident),+ => move || $body:expr) => (
{
$( let $n = $n.clone(); )+
move || $body
}
);
($($n:ident),+ => move |$($p:tt),+| $body:expr) => (
{
$( let $n = $n.clone(); )+
move |$(clone!(@param $p),)+| $body
}
);
}
which would allow more seamless cloning.
let windows_clone = windows.clone();
button.connect_clicked(move |_| {
would become
button.connect_clicked(clone!(windows => move |_| {
Why is this good?
And I just thought having some official solution to this, whether it's as simple as copying the macro code, or if it's making some new syntax, it would be awesome to have :)
New macros require RFCs, because they are insta-stable and globally visible. Please pursue this that way, thank you!
You mean I should make a pull request? Sorry, I'm a beginner regarding this.
Whoah sorry, I was confused as to what repo I was in; what you did is 100% fine. My bad! I thought you had filed this against rust-lang/rust 😓
Oh, haha. No worries :)
Would adding a Clone implementation for closures also fix this problem?
I don't think so. The macro doesn't clone the closure - it clones the specified arguments in the closure. It's sugar for writing
let thingy_clone = thingy.clone();
closure(move |test| {
thingy_clone.doStuff(test);
});
Because, as you can see, that gets quite messy.
This macro allows you to do that without temporary variables - see the example I posted.
ah yea, too bad macros can't implement traits.
Wait what? How are traits related?
I'd personally perfer blah.clone() but your macro seems like a good addition considering it isn't really possible to do it as a method.
@nixpulvis Macros can implement traits I use it in my library extensively with this macro. On top of that procedural macros can be created for auto derivation of traits.
@nixpulvis
At the bottom of http://gtk-rs.org/tuto/closures, they gave us this
blah in this context?I think some of what I have posted might be good food for thought, but within the context of this RFC proposal probably irrelevant.
I don't even know what a macro implementing a trait means (though it sounds cool), I don't really know how many compiler tricks would be needed to implement Clone for closures (I'm guessing > 0). This macro seems mostly harmless, although it's just another case of needed to know to use a macro as opposed to Rust's more natural form of abstraction.
@legolord208
blah would be something you want to clone, so in my head something implementing the Clone trait... which should cover closures I guess.I didn't mean to actually clone a closure. I meant to clone variables used inside a move closure.
This seems like a good idea. C++'s closures let you explicitly capture specific variables by copy or reference; since Rust is expressive enough to express this as a macro, we might as well do so. Given some of the discussion above, though, I think that clone! might be the wrong name for it; possibly capture_cloned! or capture_by_copy! would be more self-documenting.
I've read through some of the gtk-rs examples which use this macro and found it very hard to read. The explicit let v = v.clone(); some_func(move || ...) is far more readable and it is more obvious where cloning is required and which variables get cloned.
I'm not sure, whether the Rust language would really benefit from such a macro.
let v = v.clone() is unnecessarily verbose and not practical in many cases.
let v = ...;
let u = ...;
{ // unnecessary block
let v = v.clone();
let u = u.clone(); // this can be error-prone, ...
some_func(move || {
drop(v);
drop(u); // ...if you do similar things to `v` and `u` and they are of the same type
});
}
v.method1();
u.method2();
I agree that this macro might not be the best solution, but is useful.
FWIW, there's the enclose crate that does something very similar to this, which I use for my gtk-rs app now: https://crates.io/crates/enclose
About one year later I had a lot of use-cases where the macro would have been handy and the code would also be cleaner. Therefore I have changed my mind and propose the inclusion of a clone-like macro into the standard library.
FWIW, gtk-rs plans on making such a macro too: https://github.com/gtk-rs/gtk/issues/290
Most helpful comment
FWIW, there's the
enclosecrate that does something very similar to this, which I use for my gtk-rs app now: https://crates.io/crates/enclose