Skip to content

Warn if App::run() or App::update() are not called#5395

Closed
arnavc52 wants to merge 0 commit intobevyengine:mainfrom
arnavc52:main
Closed

Warn if App::run() or App::update() are not called#5395
arnavc52 wants to merge 0 commit intobevyengine:mainfrom
arnavc52:main

Conversation

@arnavc52
Copy link
Copy Markdown
Contributor

@arnavc52 arnavc52 commented Jul 20, 2022

Objective

  • Fixes Silent failure if app.run() is left out #5386
  • Display a warning if App::run() is not called
  • Why? Because people can accidentally delete the .run() (as mentioned in the issue). By displaying a warning, people can fix their code in seconds, instead of painstakingly debugging their entire codebase.

Solution

  • Added a #[must_use] to App with a helpful warning message
  • Print a helpful warning to the console (using either LogPlugin or good old println!) if the App is dropped without being run in a debug build.

@alice-i-cecile alice-i-cecile added C-Usability A targeted quality-of-life change that makes Bevy easier to use A-App Bevy apps and plugins labels Jul 20, 2022
@mockersf
Copy link
Copy Markdown
Member

This only warns on the code App::new();. If you add plugins or systems, then the warning won't be displayed even if you don't call run().

@mockersf
Copy link
Copy Markdown
Member

adding must_use on most functions in App doesn't work either:

The following code snippet will complain but shouldn't

let mut app = App::new();
app.add_plugins(DefaultPlugins);
app.run();

@arnavc52
Copy link
Copy Markdown
Contributor Author

arnavc52 commented Jul 20, 2022

As @mockersf just mentioned, the #[must_use] is messing up a lot of Bevy code.
What if I instead add a custom Drop implementation that throws a warning if the App is dropped without being run?

@alice-i-cecile
Copy link
Copy Markdown
Member

Hmm. A custom drop impl would be interesting. I'm curious to see what that looks like.

@alice-i-cecile
Copy link
Copy Markdown
Member

Clever! Can you add a test to verify that this keeps working?

@arnavc52 arnavc52 changed the title Warn if App::run() is not called Warn if App::run() or App::update() are not called Jul 20, 2022
@arnavc52
Copy link
Copy Markdown
Contributor Author

Clever! Can you add a test to verify that this keeps working?

Does "this keeps working" mean that the message is printed, or does it mean that it doesn't panic?

@alice-i-cecile
Copy link
Copy Markdown
Member

That the message is printed in the cases where it should be, and not when the app is run or updated.

@arnavc52
Copy link
Copy Markdown
Contributor Author

That the message is printed in the cases where it should be, and not when the app is run or updated.

Thanks!

@cdrch
Copy link
Copy Markdown

cdrch commented Jul 20, 2022

Afraid I don't have anything more useful to add, but...wow, you all are awesome. Didn't expect filing my first Bevy issue would get a PR with multiple (clever!) iterations in about half a day. You rock, Bevy rocks, and Rust rocks.

@Nilirad
Copy link
Copy Markdown
Contributor

Nilirad commented Jul 20, 2022

I found two issues:

  1. On my end, the warn! code runs but doesn't print anything on screen. Maybe the logging plugin must be configured somehow.
  2. It emits false positives for apps with a single iteration, like the hello_world example.

@zicklag
Copy link
Copy Markdown
Member

zicklag commented Jul 20, 2022

On my end, the warn! code runs but doesn't print anything on screen. Maybe the logging plugin must be configured somehow.

That might be troublesome. I'm pretty sure the Bevy log plugin has to be added or you won't get the warning. Maybe this isn't a big deal because most people will have added the DefaultPlugins by the time they forget to run the app.

@Nilirad did you add any plugins in your test where you didn't get the warning?

@Nilirad
Copy link
Copy Markdown
Contributor

Nilirad commented Jul 20, 2022

Maybe a println! could do the job? But it's inconsistent with the rest of the codebase. Also I'm not confortable with panicking.

@Nilirad did you add any plugins in your test where you didn't get the warning?

No, I just stripped the .run() from the hello_world example.

@zicklag
Copy link
Copy Markdown
Member

zicklag commented Jul 20, 2022

Maybe we can check if there's already a tracing subscriber, and if there isn't, we println, but if there is, we log.

@arnavc52
Copy link
Copy Markdown
Contributor Author

Maybe we can check if there's already a tracing subscriber, and if there isn't, we println, but if there is, we log.

Great idea!

@arnavc52
Copy link
Copy Markdown
Contributor Author

The error message does appear in the hello world example, but it comes even when the .run() is included, for some reason.

@Nilirad
Copy link
Copy Markdown
Contributor

Nilirad commented Jul 20, 2022

Is it possible to remove the flag for the release profile? It's essentially a debug check and not a soundness one.

@arnavc52
Copy link
Copy Markdown
Contributor Author

Is it possible to remove the flag for the release profile? It's essentially a debug check and not a soundness one.

Also a great idea!

@mockersf
Copy link
Copy Markdown
Member

I would rather not have a check for logger, and a fallback to println. It adds a lot of complexity to something that is a nice to have, and most people should have a logger anyway

@arnavc52
Copy link
Copy Markdown
Contributor Author

I would rather not have a check for logger, and a fallback to println. It adds a lot of complexity to something that is a nice to have, and most people should have a logger anyway

It only does that if the tracing feature is enabled for the crate. I just added some comments to make it easier to understand. Hopefully that helps!

@mockersf
Copy link
Copy Markdown
Member

It only does that if the tracing feature is enabled for the crate.

Then it's wrong... logging doesn't depend on the trace feature

@arnavc52
Copy link
Copy Markdown
Contributor Author

arnavc52 commented Jul 20, 2022

Then it's wrong... logging doesn't depend on the trace feature

LogPlugin uses tracing under the hood. Disabling the trace feature would imply that you don't want to use tracing. All of the existing tracing-based functionality in bevy_app uses the same #[cfg(feature = "trace")]

@mockersf
Copy link
Copy Markdown
Member

The trace feature is not enabled by default, and is used to control all the additional spans that are added to be able to trace executions.

Logs are using the tracing crate even without the trace feature

@arnavc52
Copy link
Copy Markdown
Contributor Author

@mockersf Thanks for clarifying it for me!

Copy link
Copy Markdown
Member

@mockersf mockersf left a comment

Choose a reason for hiding this comment

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

I don't like that it's behind debug_assertions, and I don't like the fallback to println, but the PR does what it says

@Nilirad
Copy link
Copy Markdown
Contributor

Nilirad commented Jul 21, 2022

I don't like that it's behind debug_assertions

Do you really want to ship 8 bytes of bloat to production? 🙃

@alice-i-cecile alice-i-cecile added the S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it label Jul 21, 2022
Copy link
Copy Markdown
Member

@alice-i-cecile alice-i-cecile left a comment

Choose a reason for hiding this comment

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

I like the println fallback (this is an important error message for beginners), but could go either way on the debug_assertions flag. Leaning against it; I'd probably cut it if it was my PR.

Won't block on that though.

@mockersf
Copy link
Copy Markdown
Member

I don't like that it's behind debug_assertions

Do you really want to ship 8 bytes of bloat to production? 🙃

debug_assertions detects optimised/not optimised, it has nothing to do with production. If the user is following pretty much any of the Bevy guide around here, either they will run in release or with dependency optimised and the warning will be disabled

@zicklag
Copy link
Copy Markdown
Member

zicklag commented Jul 21, 2022

either they will run in release or with dependency optimised and the warning will be disabled

That's a good point. If we want users to actually see the message, we should have that enabled even for release mode.

Almost nobody can actually play games without optimizations I think.

@Nilirad
Copy link
Copy Markdown
Contributor

Nilirad commented Jul 21, 2022

Then it could be enabled in dev profile instead. So the check is included even if dependencies are optimized. But we're really talking about a very negligible amount of data/instructions.

EDIT: Apparently there is no way to detect the build profile in conditional compilation, so the check must be done even in every build.

EDIT 2: Actually, the Cargo book shows that debug assertions are always enabled by default in the dev profile, independently from optimization level. A developer should really not debug in release profile though, but just tweak the dev profile...

@arnavc52
Copy link
Copy Markdown
Contributor Author

I got rid of the #[cfg(debug_assertions)] anyway. The performance penalty for an extra variable assignment is negligible, and rustc will likely optimize this code for release builds.

@alice-i-cecile alice-i-cecile requested a review from mockersf July 22, 2022 17:50
@alice-i-cecile
Copy link
Copy Markdown
Member

bors r+

@alice-i-cecile
Copy link
Copy Markdown
Member

alice-i-cecile commented Jul 22, 2022

bors r- (Waiting on reviews; this isn't urgent and it'll mess up the change log a bit).

@bors
Copy link
Copy Markdown
Contributor

bors bot commented Jul 22, 2022

Canceled.

bors bot pushed a commit that referenced this pull request Jul 22, 2022
# Objective

- Fixes #5386 
- Display a warning if `App::run()` is not called
- Why? Because people can accidentally delete the `.run()` (as mentioned in the issue). By displaying a warning, people can fix their code in seconds, instead of painstakingly debugging their entire codebase.

## Solution

- ~Added a `#[must_use]` to `App` with a helpful warning message~
- Print a helpful warning to the console (using either `LogPlugin` or good old `println!`) if the `App` is dropped without being run in a debug build.
@Nilirad
Copy link
Copy Markdown
Contributor

Nilirad commented Jul 26, 2022

I get no warning message in breakout.rs by just removing .run(). Using the debugger, I can see that the !self.has_run path is taken, but the rest of the code is behind a closure, so I cannot investigate more.

@alice-i-cecile alice-i-cecile removed the S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it label Jul 26, 2022
@mockersf
Copy link
Copy Markdown
Member

mockersf commented Jul 26, 2022

it just occurred to me that if this PR worked, the message would be logged twice as there are two apps created (and dropped): the main app and the renderer app.

With that, I don't think implementing drop for app is the correct solution

@arnavc52
Copy link
Copy Markdown
Contributor Author

I got rid of the part that checked if there was a logger. It didn't work and it wasn't very popular to begin with.

it just occurred to me that if this PR worked, the message would be logged twice as there are two apps created (and dropped): the main app and the renderer app.

That does happen, but I don't think it's really a problem. It's mostly just a cosmetic issue.

@tim-blackbird
Copy link
Copy Markdown
Contributor

This will always throw a warning as neither run or update is ever called on the rendering sub-app.

@mockersf
Copy link
Copy Markdown
Member

the proper way to fix this would to use the must_use flag, but that would mean changing how the app can be built. I think I would be in favour, but I would prefer to view it in action before being sure...

@alice-i-cecile alice-i-cecile added the X-Needs-SME This type of work requires an SME to approve it. label Oct 19, 2022
@arnavc52 arnavc52 closed this Jul 25, 2023
@hymm hymm mentioned this pull request Feb 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-App Bevy apps and plugins C-Usability A targeted quality-of-life change that makes Bevy easier to use X-Needs-SME This type of work requires an SME to approve it.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Silent failure if app.run() is left out

8 participants