-
-
Couldn't load subscription status.
- Fork 4.2k
[Merged by Bors] - Make Reflect safe to implement
#5010
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
Conversation
Co-authored-by: Gingeh <[email protected]>
Hopefully fix CI?
|
Nice work!
I think that's fine; this naming scheme is clearer.
I wouldn't accept this justification to make it unsafe, so I won't block on the answer here.
I like the current design quite a bit; I think it's quite clear and should be easy to use. |
I agree with the name change. Although, it should be noted that it goes against the convention we've established thus far (
I think it makes sense to move |
|
I don't remember the conclusion: do we care about implementing |
Co-authored-by: Gino Valente <[email protected]>
|
Thinking about it more, I'm wondering if
|
Co-authored-by: Gino Valente <[email protected]>
|
Just a comment on the wording: To be consistent with the Rust API guidelines, I'd suggest calling the methods (That also allows you to deprecate the previous any method and add a blanket impl for a short transition period if that is at all needed.) |
|
This PR is more or less blocked on the Unique Reflect RFC; that might wildly change what is necessary here/possibly obsolete this PR. |
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.
Like you said, I'm sure things will change a lot with the Unique Reflect RfC, but I left some comments just in case.
My main issue rn is with the inclusion of an underlying_type_id method. It could be worth it, but I'm just having a hard time getting past its possible confusions with proxy types.
crates/bevy_reflect/src/reflect.rs
Outdated
|
|
||
| /// Returns the value as a [`&mut dyn Any`][std::any::Any]. | ||
| fn any_mut(&mut self) -> &mut dyn Any; | ||
| fn as_mut_any(&mut self) -> &mut dyn Any; |
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.
Shouldn't this be as_any_mut to match the naming of other methods in the codebase?
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.
quoting the rust api guidelines:
If the mut qualifier in the name of a conversion method constitutes part of the return type, it should appear as it would appear in the type. For example Vec::as_mut_slice returns a mut slice; it does what it says. This name is preferred over as_slice_mut.
But I could accept reversing it (to as_any_mut) for consistency, as it's not in the scope of this PR to change global naming conventions.
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.
Hm yeah it might be good to rename this to as_any_mut at least to match as_reflect_mut. But we can look into renaming these according to a more Rust-approved convention later.
|
I'd be comfortable waiting for Unique Reflect for this, but if anyone else (@MrGVSV?) would also like to see this move forward first then I'll give this another pass and resolve my issues with it. Mainly I want to redo |
Yeah I think it makes sense to get this merged even before the RFC.
I don't think these changes should be part of this PR. They add new functionality that isn't directly in attempts to make
I really like the idea to include a |
|
That's fair; I suppose fixing the API is what Unique Reflect is for. I'll start working on this soon. |
crates/bevy_reflect/src/reflect.rs
Outdated
|
|
||
| /// Returns the value as a [`&mut dyn Any`][std::any::Any]. | ||
| fn any_mut(&mut self) -> &mut dyn Any; | ||
| fn as_mut_any(&mut self) -> &mut dyn Any; |
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.
Hm yeah it might be good to rename this to as_any_mut at least to match as_reflect_mut. But we can look into renaming these according to a more Rust-approved convention later.
|
I've just removed the doc links; I don't think there's a way to make them work. They won't recognize Self as |
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.
Surprisingly simple in practice; those impl files make this look way more involved than it is.
bors r+
# Objective Currently, `Reflect` is unsafe to implement because of a contract in which `any` and `any_mut` must return `self`, or `downcast` will cause UB. This PR makes `Reflect` safe, makes `downcast` not use unsafe, and eliminates this contract. ## Solution This PR adds a method to `Reflect`, `any`. It also renames the old `any` to `as_any`. `any` now takes a `Box<Self>` and returns a `Box<dyn Any>`. --- ## Changelog ### Added: - `any()` method - `represents()` method ### Changed: - `Reflect` is now a safe trait - `downcast()` is now safe - The old `any` is now called `as_any`, and `any_mut` is now `as_mut_any` ## Migration Guide - Reflect derives should not have to change anything - Manual reflect impls will need to remove the `unsafe` keyword, add `any()` implementations, and rename the old `any` and `any_mut` to `as_any` and `as_mut_any`. - Calls to `any`/`any_mut` must be changed to `as_any`/`as_mut_any` ## Points of discussion: - Should renaming `any` be avoided and instead name the new method `any_box`? - ~~Could there be a performance regression from avoiding the unsafe? I doubt it, but this change does seem to introduce redundant checks.~~ - ~~Could/should `is` and `type_id()` be implemented differently? For example, moving `is` onto `Reflect` as an `fn(&self, TypeId) -> bool`~~ Co-authored-by: PROMETHIA-27 <[email protected]>
Reflect safe to implementReflect safe to implement
| pub fn downcast<T: Reflect>(self: Box<dyn Reflect>) -> Result<Box<T>, Box<dyn Reflect>> { | ||
| // SAFE?: Same approach used by std::any::Box::downcast. ReflectValue is always Any and type | ||
| // has been checked. | ||
| if self.is::<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.
Downcast does this check internally. We should probably remove it from here.
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.
We can't without changing the error type from Box<dyn Reflect> to Box<dyn Any>
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.
Spun out into #5120.
# Objective Currently, `Reflect` is unsafe to implement because of a contract in which `any` and `any_mut` must return `self`, or `downcast` will cause UB. This PR makes `Reflect` safe, makes `downcast` not use unsafe, and eliminates this contract. ## Solution This PR adds a method to `Reflect`, `any`. It also renames the old `any` to `as_any`. `any` now takes a `Box<Self>` and returns a `Box<dyn Any>`. --- ## Changelog ### Added: - `any()` method - `represents()` method ### Changed: - `Reflect` is now a safe trait - `downcast()` is now safe - The old `any` is now called `as_any`, and `any_mut` is now `as_mut_any` ## Migration Guide - Reflect derives should not have to change anything - Manual reflect impls will need to remove the `unsafe` keyword, add `any()` implementations, and rename the old `any` and `any_mut` to `as_any` and `as_mut_any`. - Calls to `any`/`any_mut` must be changed to `as_any`/`as_mut_any` ## Points of discussion: - Should renaming `any` be avoided and instead name the new method `any_box`? - ~~Could there be a performance regression from avoiding the unsafe? I doubt it, but this change does seem to introduce redundant checks.~~ - ~~Could/should `is` and `type_id()` be implemented differently? For example, moving `is` onto `Reflect` as an `fn(&self, TypeId) -> bool`~~ Co-authored-by: PROMETHIA-27 <[email protected]>
# Objective Currently, `Reflect` is unsafe to implement because of a contract in which `any` and `any_mut` must return `self`, or `downcast` will cause UB. This PR makes `Reflect` safe, makes `downcast` not use unsafe, and eliminates this contract. ## Solution This PR adds a method to `Reflect`, `any`. It also renames the old `any` to `as_any`. `any` now takes a `Box<Self>` and returns a `Box<dyn Any>`. --- ## Changelog ### Added: - `any()` method - `represents()` method ### Changed: - `Reflect` is now a safe trait - `downcast()` is now safe - The old `any` is now called `as_any`, and `any_mut` is now `as_mut_any` ## Migration Guide - Reflect derives should not have to change anything - Manual reflect impls will need to remove the `unsafe` keyword, add `any()` implementations, and rename the old `any` and `any_mut` to `as_any` and `as_mut_any`. - Calls to `any`/`any_mut` must be changed to `as_any`/`as_mut_any` ## Points of discussion: - Should renaming `any` be avoided and instead name the new method `any_box`? - ~~Could there be a performance regression from avoiding the unsafe? I doubt it, but this change does seem to introduce redundant checks.~~ - ~~Could/should `is` and `type_id()` be implemented differently? For example, moving `is` onto `Reflect` as an `fn(&self, TypeId) -> bool`~~ Co-authored-by: PROMETHIA-27 <[email protected]>
# Objective Currently, `Reflect` is unsafe to implement because of a contract in which `any` and `any_mut` must return `self`, or `downcast` will cause UB. This PR makes `Reflect` safe, makes `downcast` not use unsafe, and eliminates this contract. ## Solution This PR adds a method to `Reflect`, `any`. It also renames the old `any` to `as_any`. `any` now takes a `Box<Self>` and returns a `Box<dyn Any>`. --- ## Changelog ### Added: - `any()` method - `represents()` method ### Changed: - `Reflect` is now a safe trait - `downcast()` is now safe - The old `any` is now called `as_any`, and `any_mut` is now `as_mut_any` ## Migration Guide - Reflect derives should not have to change anything - Manual reflect impls will need to remove the `unsafe` keyword, add `any()` implementations, and rename the old `any` and `any_mut` to `as_any` and `as_mut_any`. - Calls to `any`/`any_mut` must be changed to `as_any`/`as_mut_any` ## Points of discussion: - Should renaming `any` be avoided and instead name the new method `any_box`? - ~~Could there be a performance regression from avoiding the unsafe? I doubt it, but this change does seem to introduce redundant checks.~~ - ~~Could/should `is` and `type_id()` be implemented differently? For example, moving `is` onto `Reflect` as an `fn(&self, TypeId) -> bool`~~ Co-authored-by: PROMETHIA-27 <[email protected]>
Objective
Currently,
Reflectis unsafe to implement because of a contract in whichanyandany_mutmust returnself, ordowncastwill cause UB. This PR makesReflectsafe, makesdowncastnot use unsafe, and eliminates this contract.Solution
This PR adds a method to
Reflect,any. It also renames the oldanytoas_any.anynow takes aBox<Self>and returns aBox<dyn Any>.Changelog
Added:
any()methodrepresents()methodChanged:
Reflectis now a safe traitdowncast()is now safeanyis now calledas_any, andany_mutis nowas_mut_anyMigration Guide
unsafekeyword, addany()implementations, and rename the oldanyandany_muttoas_anyandas_mut_any.any/any_mutmust be changed toas_any/as_mut_anyPoints of discussion:
anybe avoided and instead name the new methodany_box?Could there be a performance regression from avoiding the unsafe? I doubt it, but this change does seem to introduce redundant checks.Could/shouldisandtype_id()be implemented differently? For example, movingisontoReflectas anfn(&self, TypeId) -> bool