-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Omit conditional elements without an else
branch when present in children
#3274
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Omit conditional elements without an else
branch when present in children
#3274
Conversation
55d5d08
to
8a26386
Compare
Visit the preview URL for this PR (updated for commit 97eecad): https://yew-rs-api--pr3274-html-omit-conditiona-9cjbipiu.web.app (expires Fri, 26 May 2023 16:57:33 GMT) 🔥 via Firebase Hosting GitHub Action 🌎 |
Size Comparison
|
Benchmark - SSRYew Master
Pull Request
|
b3c16a4
to
fb33158
Compare
fb33158
to
97eecad
Compare
Thank you for the pull request! However, after examining the original issue, I believe the current behaviour is intentional and correct. Here are the reasons why I think the current behaviour is correct: Rust is primarily an expression languageQuoted from Rust Reference Book:
In other words, this means that almost every piece of code that actually does something in Rust are most likely expressions. This design choice dictates several iconic language features in Rust. The main feature that is relevant in this case is expressions always produce a value. E.g.: At a glance, it might be intuitive to assume that the following code let h = html! {
<>
if b {
<span>{ "C" }</span>
}
</>
}; is roughly a syntax sugar of: let h = {
let mut nodes = VList::new();
if b {
// html! actually uses an iterator to construct children.
// This example is trying to simplify what it does in this case.
nodes.push(html! {<span>{"b"}</span>});
}
VNode::from(nodes)
}; However, if we take a look at the last expression of the if block, we can find that the block has a return type of let h = {
let mut nodes = VList::new();
nodes.push(
if b {
html! {<span>{"b"}</span>}
}
);
VNode::from(nodes)
}; The VList here is not relevant, so we can further simplify this to: let h = if b {
html! { <span>{ "C" }</span> }
}; If you try to compile the above code, Rust compiler will generate a compiler diagnostic stating that this is invalid because the else branch is missing and the complier expects the default value of this block expression to be returned ( ![]() This is not difficult to understand, as blocks are expressions, they need to evaluate to a deterministic value type. In this case, for To satisfy the compiler, one would need to write: let h = if b {
html! { <span>{ "C" }</span> }
} else {
Html::default()
}; The next question becomes: how do we interpret if expressions in To solve this situation in
The first solution is to make sure that every time an if expression is used, an else block is required. I.e.: html! {
<>
if b {
<span>{ "C" }</span>
} else {
<></>
}
</>
} I think it is not difficult to reach a conclusion that this is cumbersome to write and in many cases, an unnecessary burden imposed on Yew users. For the second solution, it should now make sense, that we make block expressions to evaluate to
|
Appreciate the detailed response @futursolo. You've convinced me this isn't the right fix. I will move my feedback to #3256 |
Description
This PR proposes a method to address the behavior described in #3256. It only changes the behavior of conditional syntax without an
else
block.To overcome the nature of the abstraction between
HtmlChildrenTree
andHtmlIf
, I've added a newtype structHtmlIfIterItem
which is used to generate tokens forHtmlIf
in this context. There is also judicious use of safe-by-inspection.unwrap()
for calls to. to_node_iterator_stream()
to avoid code duplication for this trait which returnsOption<_>
. There are likely simpler ways to do both of these things, comments welcome.I've added a test to assert/illustrate the behavior in question.
Fixes #3256
Checklist