bevyengine / bevyengine/bevy

Prefer expressions to closures in #[require()] when defining required components

Open
#17,584 4 comments 0 reactions 0 assignees View on GitHub
A-ECS C-Usability D-Macros D-Modest S-Ready-For-Implementation
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 22h
Merged PRs (30d)
161

Description

This would improve #[require(...)]. It would make the interface align more with how people actually use it. It would also reduce repetition.

#[require()] should use expressions for the default value instead of closures or functions.
This is better explained using examples.

This:
```rust
#[derive(Component)]
#[require(
MyOtherComponentA(|| MyOtherComponentA{x: 0.3, y: 0.5})
MyOtherComponentA(|| MyOtherComponentA(100))
)]
struct Foo;
```
would become this:
```rust
#[derive(Component)]
#[require(
MyOtherComponentA{x: 0.3, y: 0.5},
MyOtherComponentA(100),
)]
struct Foo;
```
Any time you are using a closure with no arguments, the expression version is simpler.

This also has the side effect of meaning Default wouldn't have to be derived for unit structs, as `Bar` in `#[require(Bar)]` would just be the expression to use.

What if you want to use a function? Just call it:
This:
```rust
#[derive(Component)]
#[require(
MyOtherComponentA(returns_component_a)
MyOtherComponentA(returns_component_b)
)]
struct Foo;
```
would become this:
```rust
#[derive(Component)]
#[require(
returns_component_a(),
returns_component_b(),
)]
struct Foo;
```
You would have to confirm that the expressions are all of different types but I think that already happens.

If you wanted to maintain the current behaviour, you could do:
```rust
#[derive(Component)]
#[require(
MyOtherComponentA::default()
MyOtherComponentB::default()
)]
struct Foo;
```
Or the macro could try and use a default constructor if just the struct name is specified.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.