Feedback on Relm4's view macro. #461
Replies: 4 comments 3 replies
-
Let's summarize the previous discussions about declarative and what features could be implemented in Relm4. Architectural changesDeclarative does not require a trait nor a built-in runtime for interactivity, whereas Relm4 requires you to use messages to modify state. The underlying code generation is not fundamentally different, but rather it is about where the code is put by the macro. Declarative (ab)uses Rust's attribute macros to do something like this: #[view { /* enter your widgets here */ }]
fn some_function() {
// This is still part of the macro
} This solves the problem that you need both the Instead, I would rather like to explore using different traits, maybe a even more reduced version of the old Syntax changesIf you use a Attributes are replaced by custom syntax or are instead written as lifetimes. The reduction of attributes makes the code look more elegant, but does not necessarily improve the readability. This alone should probably have it's own dedicated discussion and I don't have time to summarize everything, currently. In declarative, arguments are passed by specifying the method after the widget type and then using And also Conditional widgets++Conditional widgets (using Replacing synThis has nothing to do with the previous discussions, but I'd like to replace syn in the future. Syn still feels like a workaround even after years of development and has a lot of rough edges. To be fair, this has also to do with the limited APIs of the Rust compiler, but I think it's about time to challenge the status quo. I think a successor to syn should be more opinionated. Good macros should always have three stages: parsing, internal logic and code generation. Syn makes it possible to mix everything together, but parsing and code generation could be largely automated by macros and only the internal logic should be imperative code. Syn supports parsing files, but doesn't parse comments and blank lines which makes it basically impossible to build a formater for Relm4 without duplicating the parsing logic of the macro. Together with the automated parsing logic, it should be possible to define where you want line-breaks and offer formatting at almost no extra effort for the user. ConclusionThere is still a lot more to be discussed, but I don't have more time now, so feel free to complete this summary and share your thoughts! We might even need to split this discussion into smaller topics to keep track of everything in the future. |
Beta Was this translation helpful? Give feedback.
-
Greetings. You will excuse the idiomatic errors since I use the translator a lot. I guess I'm correct in saying that while Relm4 focuses on giving more through more features, the So Eventually I will answer some issues with |
Beta Was this translation helpful? Give feedback.
-
Thanks @ejaa3 for your comments! I wrote down some of my thoughts here, but I had limited time, so some ideas might not be complete yet. View syntaxI don't think Relm4 should use attribute macros like declarative does it. When looking at the rust lang reference, it becomes clear that attribute macros are supposed to work similar to built-in attributes and should have only few additional parameters (also, declarative even breaks syntax highlighting in some editors because nobody even considered the possibility to (ab)use macros like this). I don't know a single crate that does things differently except for the current version of declarative. Therefore, I think we should always wrap the macro around a trait implementation to avoid unidiomatic code, roughly something like this: #[some_view_macro(some_params)]
impl SomeTrait for Data {
view! {
// widgets...
}
fn some_method() {
expand_view_here!();
}
} Placing namesI think allowing to name widgets after the type like declarative and blueprint do it is a good idea. It removes the need for the name attribute and would also remove the old gtk::Box my_box {
gtk::Label my_label {
// ...
}
} Placing methodsRelm4's syntax is similar to Rust (struct initialization), JSON and blueprint which makes it easy for beginners to understand the macro and also makes it very consistent. Therefore, I don't like the old C-style of doing things in the opposite order and rather like to have the type after the method name. I think that the idea with the argument specification is really nice though. gtk::Box my_box {
append(&#) = gtk::Label my_label {
// ...
},
// It probably makes sense to add a shorter syntax and
// automatically add a reference because that covers at least 90% of all use-cases
append = gtk::Label my_label {
// ...
}
} Builder pattern syntaxI really like the idea of making it easier to use builder patters, but I'm still not convinced by the approach declarative uses. While waiting for my train, I thought of another interesting approach: We could just allow the user to return a builder type (or any other type) by using relm4::view! {
adw::Flap::builder() my_flap {
flap_position: gtk::PackType::End,
fold_policy: adw::FlapFoldPolicy::Never,
gtk::Box the_flap {
// content
},
gtk::Box the_content {
// content
},
// FlapBuider -> Flap
#build(),
set_flap_position: //...
}
} AttributesI don't have a lot of time, so I'll just write down my thoughts quickly. I think gtk::Box {
@update
set_margin_all: model.margin,
gtk::Label {
@update if let Some(text) = &model.text
set_label: text,
},
gtk::Label {
// Apply update to both properties
@update if model.update_label
> set_label: model.label,
> set_margin_all: model.label_margin,
}
} |
Beta Was this translation helpful? Give feedback.
-
Wrapping in a traitAt least to me it looks pretty clear that attribute macros are supposed to extend built-in attributes. And Rust's syntax for attributes is in fact very limited as the reference and the syn crate show. Just because we get a Therefore and also because there are no big downsides, I'd prefer a trait implementation or maybe we could actually use modules as well. Placing methodsIf I understand you correctly, there is no good reason against putting the method first. The idea of allowing the user to specify the interpolation within the bracket is pretty good as you demonstrated. Builder pattern syntax
No, the |
Beta Was this translation helpful? Give feedback.
-
Please read #450 for context.
Beta Was this translation helpful? Give feedback.
All reactions