-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Implicit optional attributes #1637
Conversation
it's gonna be gone soon anyway *shrugs*
@jstarry, I'd love to hear your thoughts on the following two points: 1. Unifying attributes with propsAttributes now behave like a prop with type 2. Pesky transformationsRust really doesn't like it but now we do actually need to have a "transformer" trait to support implicit optional attributes. The So far we haven't introduced any type conversions, we've basically only expanded on Rust's type coercions, but there's at least one area where we want to allow some type conversions: strings. Specifically, we want This is where the problem begins. In an ideal world we could just implement the clone conversion as
If we want to support the Btw, the situation isn't all that different from before, it's just that the new optional attributes really makes this problem obvious. |
@siku2 sorry for the delay. First off, I whole-heartedly agree with your stated goals. As for your two points, I just skimmed and your arguments seem reasonable but I haven't expended any serious thought into it. I trust your knowledge over the finer details of Rust's type system over my own at this point. That being said, I'd like to learn more and I can find time over the weekend to dive into this more if you would like to talk things out more. But if you're pretty comfortable with the current direction, by all means blaze ahead 👍 |
@jstarry I was hoping your input might give me some inspiration. If you do happen to come up with an idea, as crazy as it might be, I would love to hear it. Oh and I'd also love to know which transformations (if any?) you think are essential. |
Yeah, I think it's ok to skip those.
I think it's better to have the clones be explicit and avoid adding the
Do we? |
Actually this would be really nice for callbacks |
Yeah, I originally wanted to remove implicit cloning altogether but I think it's really nice for things like
We don't really, but I don't think it's harmful either. I added it because many components accept |
Hey @siku2 what are your latest thoughts on this PR? Think it's ready to come out of draft mode? When we make a decision on it, I would like to have it cherry picked to the v0.18 branch after merging to master |
@jstarry It's been a while but I think the issue still lies with the ergonomics of it all. I think I was unhappy with how complex the rules still are... I'll try to get this up to speed as soon as possible but at this point I certainly wouldn't mind if someone else got there before me :P |
## Transformers | ||
|
||
Whenever you set a prop its value goes through a transformation step first. | ||
If the value already has the correct type, this step doesn't do anything. | ||
However, transformers can be useful to reduce code repetition. | ||
|
||
The following is a list of transformers you should know about: | ||
|
||
- `&T` -> `T` | ||
|
||
Clones the reference to get an owned value. | ||
|
||
- `&str` -> `String` | ||
|
||
Allows you to use string literals without adding `.to_owned()` at the end. | ||
|
||
- `T` -> `Option<T>` | ||
|
||
Wraps the value in `Some`. | ||
|
||
```rust | ||
struct Props { | ||
unique_id: Option<usize>, | ||
text: String, | ||
} | ||
|
||
struct Model; | ||
impl Component for Model { | ||
type Properties = Props; | ||
|
||
// ... | ||
} | ||
|
||
// transformers allow you to write this: | ||
html! { <Model unique_id=5 text="literals are fun" /> }; | ||
// instead of: | ||
html! { <Model unique_id=Some(5) text="literals are fun".to_owned() /> }; | ||
``` | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed the entire section here. I added a note about Into<Option<T>>
later on.
<@{format!("h{}", level)} class="title">{ content }</@> | ||
<@{format!("h{}", level)} class="title">{ text }</@> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be better if the tests were executed 😞
docs/concepts/html/elements.md
Outdated
Most HTML attributes can be marked as optional by placing a `?` in front of | ||
the `=` sign. This makes them accept the same type of value as otherwise, but | ||
wrapped in an `Option<T>`: | ||
Most HTML attributes can use optional values (`Some(x)` or `None`). This allows | ||
to omit the attribute if the attribute is marked as optional. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to put things simply. But any advice are welcome 😅
Please note that it is also valid to give only the value as properties behave | ||
like `Into<Option<T>>`: | ||
|
||
```rust | ||
let id = "foobar"; | ||
|
||
html! { | ||
<div id=id></div> | ||
} | ||
``` | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the remark I added about the optional attributes.
|
||
impl ImplicitClone for NodeRef {} | ||
impl<Comp: Component> ImplicitClone for Scope<Comp> {} | ||
// TODO there are still a few missing like AgentScope |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did the AgentScope... Can someone help me enumerate what else is missing? 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't think of anything else that is missing. In the worst case, the user will have to call clone
if this trait isn't implemented. Let's just roll with it for now. We'll know what's missing once this code is merged and used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fine by me
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like the failing CI is because of new Clippy lints introduced in Rust 1.51. #1801 fixed those in master so I believe it can be rebased here too.
.pop("class") | ||
.map(|prop| ClassesForm::from_expr(prop.value)); | ||
let value = props.pop("value"); | ||
let kind = props.pop("type"); | ||
let checked = props.pop_nonoptional("checked")?; | ||
let checked = props.pop("checked"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any reason why these 4 are special cased?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No idea...
// TODO there are still a few missing like AgentScope | ||
|
||
/// A trait similar to `Into<T>` which allows conversion to a value of a `Properties` struct. | ||
pub trait IntoPropValue<T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we implement this for T
and &T
where T: ToString
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No... I think it's because of specialization
Co-authored-by: Muhammad Hamza <muhammadhamza1311@gmail.com>
…ests (yewstack#1801) * update rust version for macro test to 1.51 * enable const generic tests * run integration tests using MSRV * am blind * clippy, fmt * apply suggestion
Co-authored-by: Muhammad Hamza <muhammadhamza1311@gmail.com>
Thanks a lot!! I cherry-picked 🙏 |
Description
See #1550 for further details.
This is still very WIP but from the looks of it this is gonna require A LOT of breaking changes.
Closes: #1550
Closes: #1623 (this was required to support optional
prop_or*
)Goals
Transformer
trait. It's already very confusing and it just keeps getting worse. Moves complexity out of the macro making it more transparent.Transformer
trait. It's no longer possible to sustain all of them without specialization. They also make it very easy to write suboptimal code because they obscure what's happening under the hood.TODO
Option<T>
types.#[prop_or*]
can't be used for this because types end up beingOption<Option<T>>
which is very confusing. (done by @cecton)