Skip to content

Remove incorrect equality comparisons for asset load error types #14428

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

Closed
wants to merge 14 commits into from

Conversation

joseph-gio
Copy link
Member

@joseph-gio joseph-gio commented Jul 21, 2024

Objective

The type AssetLoadError has PartialEq and Eq impls, which is problematic due to the fact that the AssetLoaderError and AddAsyncError variants lie in their impls: they will return true for any Box<dyn Error> with the same TypeId, even if the actual value is different. This can lead to subtle bugs if a user relies on the equality comparison to ensure that two values are equal.

More generally, it is an anti-pattern for large error types involving dynamic dispatch, such as AssetLoadError, to have equality comparisons. Directly comparing two errors for equality is usually not desired -- if some logic needs to branch based on the value of an error, it is usually more correct to check for specific variants and inspect their fields.

As far as I can tell, the only reason these errors have equality comparisons is because the LoadState enum wraps AssetLoadError for its Failed variant. This equality comparison is only used to check for == LoadState::Loaded, which we can easily replace with an is_loaded method.

Solution

Remove the {Partial}Eq impls from LoadState, which also allows us to remove it from the error types.

Migration Guide

The types bevy_asset::AssetLoadError and bevy_asset::LoadState no longer support equality comparisons. If you need to check for an asset's load state, consider checking for a specific variant using LoadState::is_loaded or the matches! macro. Similarly, consider using the matches! macro to check for specific variants of the AssetLoadError type if you need to inspect the value of an asset load error in your code.

@joseph-gio joseph-gio added C-Bug An unexpected or incorrect behavior A-Assets Load files from disk to use for things like images, models, and sounds labels Jul 21, 2024
@alice-i-cecile alice-i-cecile added the M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide label Jul 21, 2024
@alice-i-cecile alice-i-cecile added this to the 0.15 milestone Jul 21, 2024
Copy link
Member

@MrGVSV MrGVSV left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems more correct to me. I also like the methods. It feels cleaner than having users use matches! directly.

Comment on lines +1351 to +1354
// NOTE: an `is_not_loaded` method is intentionally not included, as it may mislead some users
// into thinking it is complementary to `is_loaded`.
// `NotLoaded` is a very specific failure mode and in most cases it is not necessary to directly check for it.
// If this is necessary the `matches!` macro can be used instead of a helper method.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated to this PR but it might be worth renaming the NotLoaded variant to Idle or something to help clarify the distinction on the enum itself.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There might be a better name, but I like how NotLoaded avoids making any statements about the asset. If an asset handle is NotLoaded, it could mean that it hasn't started loading yet, or it could mean that there is no asset associated with the handle and never will be, or that the handle is invalid. A name like Idle implies that the asset does exist in some form which isn't necessarily true

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh good point, I hadn't considered that 🤔

Comment on lines +1356 to +1361
/// Returns `true` if the asset is loaded or in the process of being loaded. If true true,
/// then the asset can be considered to be in a "normal" state: the asset either exists
/// or will exist, and no errors have been encountered yet.
pub fn is_loaded_or_loading(&self) -> bool {
self.is_loaded() || self.is_loading()
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a common thing yo check for? I imagine you'd generally want to handle these two cases separately, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not tied to this method, I'd be okay with removing it. I just imagined that some users would want a quick way of checking if an asset is in a valid state or not, and allowing you to call is_loaded and is_loading in a single call allows you to avoid binding a LoadState to a local

@alice-i-cecile alice-i-cecile added the S-Needs-Review Needs reviewer attention (from anyone!) to move forward label Oct 3, 2024
@alice-i-cecile alice-i-cecile added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Oct 3, 2024
@alice-i-cecile
Copy link
Member

@JoJoJet if you resolve merge conflicts I'll get this in.

@alice-i-cecile alice-i-cecile removed this from the 0.15 milestone Oct 3, 2024
@alice-i-cecile alice-i-cecile added S-Adopt-Me The original PR author has no intent to complete this work. Pick me up! and removed S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it labels Oct 7, 2024
@BenjaminBrienen
Copy link
Contributor

Adopted in #15890

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Assets Load files from disk to use for things like images, models, and sounds C-Bug An unexpected or incorrect behavior M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide S-Adopt-Me The original PR author has no intent to complete this work. Pick me up!
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants