> For the complete documentation index, see [llms.txt](https://wise-shepherd-games.gitbook.io/theia-ecs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://wise-shepherd-games.gitbook.io/theia-ecs/execution/queries.md).

# Queries

Walks entities matching a composition

A query is Theia's **iteration primitive**. It walks entities **matching a component composition** and delivers their **component data by reference**, directly from archetype storage: **dense blittable arrays laid out contiguously in memory**.

Regarding the elements themselves, there is **no pointer chasing** (cache-coherent blittable structs)**, no boxing, no heap allocation during iteration**. The component reference passed to the callback aliases the storage reference directly, so **mutations persist**.

Queries are **strictly typed through generics**. The component types are enforced at query creation and callback definition by the compiler, with **no runtime type resolution or casting**. This also means auto-completion guides the boilerplate from the first keystroke.

**Queries are created via the world**, once before the simulation starts, and **reused every tick**. Creating a query is a structural operation on the world and throws if any query is currently executing or a deferred flush is in progress.

#### Why Struct Callbacks, Not Delegates

Queries **do not use** `Action<>` **delegates**! The iteration loop runs hot every tick **across potentially thousands of entities**; a delegate that captures any local variable allocates **a closure object on every call**, which is **measurable GC pressure** at that frequency.&#x20;

Struct callbacks live on the stack; any state they need goes on the struct itself as fields, **which costs nothing**. With `where T : struct`, the **JIT devirtualizes** the call and **inlines** `Execute` **directly** into the iteration loop.

{% hint style="info" %}
`ref struct` implementations can also hold spans and other stack-only data that a delegate cannot capture at all.
{% endhint %}

Other frameworks offer struct callbacks as an opt-in alongside delegates. Theia **makes struct callbacks the only path**; the performance benefits are too significant to leave as an option, and **removing the** **delegate surface eliminates the temptation entirely**.

{% hint style="info" %}
[Events](/theia-ecs/events.md) use `Action<>` because the subscription model, wiring handlers via `+=`, requires a delegate either way. **There is no such constraint at a query call site.**&#x20;

The callback is passed directly and consumed immediately, so a struct is both possible and the right choice.&#x20;

`QueryRelation`, `QueryEvaluatedRelation`, and the `QueryUnique` follow the same struct callback pattern.
{% endhint %}

Although struct callbacks like these can be source generated, doing so **hides the essential iteration logic from the developer consuming the API**. Queries **should be declared explicitly**: the **predictability and readability** of the code **is worth the few lines of boilerplate**.

#### Two Query Shapes

`SettlerQuery` is **bound to a single assemblage's archetype at creation time**. It iterates exactly that archetype with **no matching cost**, the **storage slot for each component is cached** and the **iteration loop goes straight to work**.&#x20;

Use `SettlerQuery` when the entities to visit **all share one composition** and that **composition is stable during the simulation**; meaning those entities never gain or lose components. The moment a dwarf gains a `Stunned` component it transitions to a different archetype and **falls outside the settler's view**.

`NomadQuery` matches every archetype whose composition **contains the requested components**. It maintains a cached list of matched archetypes, **appended incrementally as new archetypes appear** in the world. Use `NomadQuery` when the target entities may span multiple compositions.

#### Creating Queries

Both query types are created via the world and go up to T16:

```csharp
/* SettlerQuery is bounded to a specific assemblage's archetype */
Assemblage<Transform, Health, Axe> dwarf =
    world.CreateAssemblage<Transform, Health, Axe>();

SettlerQuery<Transform, Health, Axe> dwarfQuery =
    world.CreateSettlerQuery(dwarf);

/* NomadQuery matches every archetype containing Health */
NomadQuery<Health> healthQuery =
    world.CreateNomadQuery<Health>();
```

#### Callback Contracts

Two interfaces define the callback shape:

`IForEach<T>` receives **only the component data**, not the entity handle. Use this when the callback does not need to know which entity owns the component; the iteration loop **skips loading the entity span entirely**:

```csharp
/* 
    Movement callback only needs transform and velocity, 
    not the entity handle
*/
public ref struct MoveForEach : IForEach<Transform, Velocity>
{
    public void Execute(ref Transform transform, ref Velocity velocity)
    {
        transform.Position.X += velocity.X * 0.16f;
        transform.Position.Y += velocity.Y * 0.16f;
    }
}
```

`IForEachEntity<T>` receives **both the entity handle and the component data**. Use this when the callback needs to act on the entity itself: queuing a deferred command, checking a relation, or accessing other components.

```csharp
/* 
    Combat callback needs the entity handle to 
    queue deferred ghoulification
*/
public ref struct CombatForEach : IForEachEntity<Health>
{
    public readonly World World;

    public void Execute(Entity entity, ref Health health)
    {
        health.Current -= 10;

        if (health.Current <= 0)
            World.DeferredGhoulify(entity);
    }
}
```

`ref struct` implementations can hold spans and refs as fields. Also, passing as ref, allows **state** on the struct to be persisted **across entity visits**, enabling patterns like accumulating a sum, collecting results, or carrying a stack-only view into world state across the entire iteration **without any heap involvement**.

#### Iteration Shapes

Both query types expose four iteration shapes:

Sequential, providing the callback by `ref`:

```csharp
/* Without entity handle */
MoveForEach moveForEach = new MoveForEach();
movementQuery.ForEach(ref moveForEach);

/* With entity handle */
CombatForEach combatForEach = new CombatForEach() { World = world };
combatQuery.ForEachEntity(ref combatForEach);
```

Parallel, providing the callback by value:

```csharp
/* Without entity handle */
MoveForEach moveForEach = new MoveForEach();
movementQuery.ForEachParallel(moveForEach);

/* With entity handle */
CombatForEach combatForEach = new CombatForEach() { World = world };
combatQuery.ForEachEntityParallel(combatForEach);
```

Sequential iteration **takes the callback by** `ref`, the callback can be a `ref struct`. Parallel iteration **takes the callback by value** because **each chunk's job receives its own copy**; the callback cannot be a `ref struct` in that case.

All four shapes **increment the world's queries-executing counter on entry and decrement it on exit**. **Structural changes throw while the counter is non-zero**; queries themselves must not throw. To make structural changes during iteration, use deferred commands and flush after iteration completes. See [Deferred Commands](/theia-ecs/entities-and-composition/deferred-commands.md) and [Iteration Safety](/theia-ecs/execution/iteration-safety.md).

```csharp
/* 
    Returns true if any query is currently 
    iterating on this world
*/
world.AreThereAnyQueriesBeingExecuted();
```

#### Incremental Matching

`NomadQuery` maintains a cached list of matched archetypes. When a new archetype is created in the world, either "directly" via Assemblage creation or as a result of a component add or remove transitioning an entity, every registered `NomadQuery` whose composition is satisfied by the new archetype has it appended to its list automatically. **Iteration is a straight walk over that cached list**; there is no per-iteration re-scan, and no developer intervention required.

This means structural changes that move entities between archetypes are reflected in query results automatically:

<pre class="language-csharp"><code class="lang-csharp">Assemblage&#x3C;Health, Ugliness> orc = world.CreateAssemblage&#x3C;Health, Ugliness>();

/* Matches any entity with Health */
NomadQuery&#x3C;Health> healthQuery = world.CreateNomadQuery&#x3C;Health>();

/* Matches any entity with Poisoned */
NomadQuery&#x3C;Poisoned> poisonedQuery = world.CreateNomadQuery&#x3C;Poisoned>();

Entity uglyOrc = orc.Create(
    new Health() { Current = 80, Max = 80 }, 
    new Ugliness() { Value = 10.0f }
);

/* uglyOrc is visible in healthQuery, not in poisonedQuery */

world.TryAddComponent&#x3C;Poisoned>(uglyOrc, new Poisoned() { Duration = 5f });

/* 
    (1) uglyOrc is now visible in poisonedQuery too... no query update needed! 
<strong>    (2) healthQuery still sees uglyOrc since Health is still part of its composition 
</strong><strong>*/
</strong></code></pre>

#### Recommended Setup Order

Is **highly recommended to follow this order** at world construction time:

1. Create all assemblages: `world.CreateAssemblage<...>()` ;
2. Create all settler queries: `world.CreateSettlerQuery(...)` ;
3. Create all nomad queries: `world.CreateNomadQuery<...>()` .

`NomadQuery` seeds its matched-archetype list at creation time by scanning all archetypes currently registered on the world, previously triggered by assemblage creation.
