# Bevy 0.17 Event trait split
## Motivation
Bevy now has a number of different flavors of event.
Each of these flavors have their own tradeoffs: it's not possible or helpful to flatten these down to a single kind of event that meets all of the needs.
In Bevy 0.16, these are lumped together into a single `Event` trait.
While this reduces boilerplate and decision-making when defining new event types, this has several drawbacks:
- when reading the code and documentation, the trait does not tell you how the event should be used
- the shared trait allows users to silently misuse our APIs, creating frustrating bugs
- events sent via one mechanism will not be seen by the other mechanism
- calling `On::entity` on a broadcast event will always return `Entity::PLACEHOLDER`
- because there's no distinction between broadcast and entity events, we need to either return `Entity::PLACEHOLDER` (nulls!) or an `Option` in critical APIs like `On::entity`
- we need to define trait properties (like event propagation) that are completely unused / unneeded
## Proposed design
Bevy provides three types of events, each with their own trait:
- `BufferedEvent`
- for pull-based events, enabling efficient batch processing and carefully ordered event evaluation
- read by `EventReader`
- sent by `EventWriter`
- `EntityEvent`
- for push-based events that target a specific entity, enabling bubbling and propagated chains
- read by observer systems using`On`
- sent by `commands.trigger_targets()`
- `BroadcastEvent`
- for push-based events that don't target a specific entity, avoiding the need to create and target dummy entities
- read by observer systems using`On`
- sent by `commands.trigger()`
`EntityEvent` and `BroadcastEvent` share common infrastructure and the `On` system param. As a result, they also share a `ObserverEvent` supertrait. `ObserverEvent` is automatically incldued in the `EntityEvent` and `BroadcastEvent` derives.
`On::entity()` (and similar methods) requires `E: EntityEvent`. This allows us to safely return a non-optional `Entity`. However, if users implement both `BroadcastEvent` and `EntityEvent`, `Entity::PLACEHOLDER` may still be returned.
`EntityEvent` observers can still choose to watch entities. Entity observers which do not watch any entities are called "universal observers", and will trigger when any entity event of the matching type is sent.
Entity-watching observers will only trigger if the entity-events' target is in the set of entities that they are watching.
## Alternatives considered
### Shared Event trait between all types of events
We could use the proposed design, or any similar design, and add a `Event` supertrait, i.e. `ObserverEvent: Event` + `BufferedEvent: Event`.
While this wouldn't cause any real problems (because the API would be gated by the stricter subtraits), it also wouldn't do any good: there's no shared infrastructure, and an `E: Event` trait bound never be used by users anywhere.
### Unify broadcast and buffered events
Entity events fundamentally differ from broadcast and buffered events because they need to store information about the entity being targeted, seperately from the actual data of the struct.
We could conceivably merge broadcast and buffered events in some ways though, as their data is the same.
The simplest approach is to simply mirror the events by cloning them:
1. For each event sent by an `EventWriter`, also emit a command to send it as a buffered event, by baking `Commands` into `EventWriter`.
2. For each broadcast event registered, create an observer which mirrors the events via an `EventWriter`.
This is very wasteful!
It also introduces an `Event: Clone` trait bound, which will break users in surprising ways that are often very hard to mitigate.
Ultimately, we should leave this decision in the hands of the event authors: if users are clamoring for access to both mechanisms, they can mirror their event streams themselves.
### Just get rid of buffered events
In some ways, buffered events feel like a less robust subset of broadcast events. However, they have several key advantages:
1. Users can carefully control the order in which events are read by various systems, or delay reading them.
2. Reading and writing large numbers of events has much lower overhead.
3. Buffered events can be mutated.
4. Event readers can see multiple events at once.
While we can conceivably improve various elements of this, the design goals are too divergent. Long-term, most of Bevy's first-party events probably make more sense as observer events of various forms, but buffered events will always have a place in high-throughput systems (like physics).
### Mutually exclusive `EntityEvent` and `BroadcastEvent` traits
Via sealed traits and associated types, we can make `EntityEvent` and `BroadcastEvent` mutually exclusive.
Doing so would completely eliminate the possibility of returning `Entity::PLACEHOLDER` via `On`. That's nice!
However, it prevents authors from deliberately implementing both traits. Bevy uses this in one case, for `SceneInstanceReady`, although the value is unclear, both here and in general.
More importantly though, it complicates both the implementation and documentation of these traits, and breaks `Box<dyn ObserverEvent`> due to the associated type.
Simple restricting entity-returning methods to `EntityEvent` is quite clear and robust to 99% of misuse: we think that's good enough.
### Distinct `On` vs. `Receive` system param
Rather than relying on trait-restricted methods for `On`, we could instead replace it with a broadcast-event equivalent, called `Receive`.
This would make the signature of observer systems clearer about the type of event they're receiving, and in theory, could make it easier for beginners to read the documentation to understand available mechanisms.
However, this would be a significant duplication of code (the observer system machinery will also need duplication), and make refactors between observer event flavors harder. We don't think this is worth it.
### `PropagatingEvent` subtrait
We could take this trait split another level further, and move information about how events propagate to a subtrait of `EntityEvent`.
This would reduce code generated, be conceptually cleaner and make manual implementations of `ObserverEvent` easier. It would also allow us to gate `On::original_target` and similar methods to only work for `E: PropagatingEvent`.
This proposal has not been seriously discussed yet. It might be worth doing, but it can easily be done in follow-up, even after 0.17 ships.