gtk-rs-core icon indicating copy to clipboard operation
gtk-rs-core copied to clipboard

[FEATURE REQUEST] `use_cloned!` macro

Open ranfdev opened this issue 3 years ago • 4 comments

I propose adding a use_cloned! macro with the following semantics:

button.connect_clicked(use_cloned![move |_btn| {
  weak!(label, panic).set_label("clicked the button");
  strong!(label2).set_label("I'm strong");
}]);

Benefits:

  • Formatting from rustfmt I found out that by using the same macro format as vec![expr1, expr2, ...] rustfmt can format the macro as a vec![]. The content of this macro is always a valid rust expression, so everything works out.
  • Easier to use The cloning happens automatically, no need to specify what you need beforehand. Just wrap the variable you want to use with strong! or weak!.

Implementation details I have a basic working implementation (~50 lines) based on macro_rules. It has the following drawbacks:

  • Each variable can only be cloned one time in the same use_cloned! block. This can be solved by writing the implementation using proc macros
  • You can't nest the strong! and weak! macros inside another macro. Eg: You can't do println!("{:?}", cloned!(a)). This can be solved if needed.

What do you think?

ranfdev avatar Sep 18 '22 16:09 ranfdev

Formatting from rustfmt

That would be good to have but it's a bit ugly to use vec syntax here. We could get the same behaviour with an attribute macro though.

  • This can be solved by writing the implementation using proc macros

I think you lose the rustfmt support with the vec-style macro again then.

  • The cloning happens automatically, no need to specify what you need beforehand.

IMHO that's an anti-feature :) Having to specify exactly what you need upfront makes it clear when reading the code what exactly happens there.

sdroege avatar Sep 21 '22 08:09 sdroege

About the formatting: With more testing, I found out that rustfmt seems to not care about the definition of the macro; it only cares about how the macro gets used. As long as the macro call contains an expression, the expression will get formatted. And the formatting works with both round brackets, (), and square brackets. Not {}.

Having to specify exactly what you need upfront makes it clear when reading the code what exactly happens there.

I think who wants complete control over the cloning behavior is going to clone everything manually anyway. Cloning is inevitable, so why not make it painless?

Anyway, I will probably just make a separate crate for this.

ranfdev avatar Sep 22 '22 11:09 ranfdev

See the clone_block macro I made for an example of how to do it using an attribute: https://github.com/jf2048/gobject#clone_block-macro

The idea is to get it a bit closer to how captures are specified in C++ and Swift

jf2048 avatar Sep 29 '22 23:09 jf2048

I've been thinking about trying a more rustfmt-friendly syntax with attributes, too:

clone!(
  #[weak]
  foo,

  #[strong(name = baz)]
  self.bar,

  move |_, _| {
    println!("{}", baz);
  }
)

euclio avatar Jan 22 '23 17:01 euclio