# Args

`Args` is the pooled execution context passed to every Instruction, Condition, Trigger, and Signal. It carries **Source**, **Target**, and named parameters so nested logic can act on the current objects and values.

## What it carries

The context identifies the objects involved and carries any extra values the running logic needs:

| Member | Is |
| :--- | :--- |
| `Source` | The `GameObject` the running logic belongs to — for a Trigger, the object holding the Event. |
| `Target` | The other `GameObject` involved. |
| Parameters | Named, typed extra values — loop item, index, count, and anything you add. |

This Instruction reads the current **Target** from its context:

```cs
protected override Awaitable Run(Args args)
{
    GameObject who = args.Target;
    Debug.Log($"Acting on {who.name}");

    return Done;
}
```

`args.Target` resolves to the other object supplied by the Trigger or caller. Designers use the same context through [Source & Target](../manual/events/source-target.md).

## Args instances are pooled

`Args` instances are recycled. Reading one after release produces values from a later use rather than an exception.

Never construct one directly. Get one from the pool and dispose it:

```cs
using Args args = Args.Get(this.gameObject, target);
this.m_Instructions.Run(args, this);
```

The `using` declaration returns the instance to the pool at the end of the scope. Use the same ownership pattern for every acquired instance.

!!! warning "Never store an Args reference"
    Caching an `Args` in a field, capturing it in a long-lived closure, or holding it across frames means you're reading whatever the pool later put in that slot.

    When context must survive inside a subscription, copy it with `Args.Get(args)`. The copy is independent and must be disposed when the subscription ends.

In the editor, accessing a disposed `Args` logs an error. Builds omit this check, so fix every reported use-after-release before shipping.

## Getting one

| Overload | Use when |
| :--- | :--- |
| `Args.Get()` | You need an empty context. |
| `Args.Get(source, target)` | You have both objects. Accepts `GameObject` or `Component`. |
| `Args.Get(args)` | You need an independent copy of an existing context. |
| `Args.None` | You need a shared, permanently empty context. Never dispose it. |

`Args.None` is a singleton for context-free calls. Because it's shared, don't write to it.

## Reading components

Two shortcuts avoid a `GetComponent` on every access:

```cs
Rigidbody body = args.TargetComponent<Rigidbody>();
Animator anim = args.SourceComponent<Animator>();
```

`TargetComponent` and `SourceComponent` use a per-object component cache, avoiding repeated Unity lookups after the first successful search.

## Parameters

Beyond **Source** and **Target**, `Args` carries named values. **Foreach** uses parameters for the current item, and custom Instructions use them to pass data into nested lists:

```cs
args.SetParameter(MY_PARAMETER, someValue);

if (args.TryGetParameter(MY_PARAMETER, out int value))
{
    // …
}
```

`SetParameter` stores an exact type under a `PropertyName`. Read with `TryGetParameter` when the type must match, or `TryConvertParameter` when conversion is valid.

| Method | Does |
| :--- | :--- |
| `SetParameter<T>(id, value)` | Stores a typed value. |
| `TryGetParameter<T>(id, out value)` | Reads it back, requiring an exact type match. |
| `TryConvertParameter<T>(id, out value)` | Reads it back, converting if needed. |
| `ContainsParameter(id)` | Tests presence. |
| `ClearParameter(id)` | Removes it. |
| `GetParameterGameObject(id)` | Reads it as a `GameObject`, unwrapping a `Component` if necessary. |

Identifiers are `PropertyName` values, which compare by hash rather than by string. Declare them once as `static readonly` fields; do not build them per call.

Collection loops use the parameters defined in `ArgsCollectionParameters`: item, index, and count.

## Declaring a parameter scope

For a parameter to appear in the Signal dropdowns of a nested list, the containing Instruction declares which of its fields provide it:

```cs
bool IParameterScope.ProvidesParameter(string member, PropertyName parameter)
{
    return member == nameof(this.m_Instructions)
        && ArgsCollectionParameters.Contains(parameter);
}
```

Without this declaration, code can still read the value at runtime, but designers can't select it in the nested list's Signal dropdowns.

## Copying and nesting

`Args.Get(args)` copies **Source**, **Target**, and every set parameter into a fresh instance. Nested lists use this so that changes made inside a loop don't affect the outer context.

**Foreach** is the canonical example: it copies the context, overwrites `Target` per iteration, and the outer context is untouched when the loop ends.

## Where to go next

- **[Source & Target](../manual/events/source-target.md)** — compare the designer-facing context model.
- **[Custom Instructions](extending/instructions.md)** — use `Args` inside a node.
- **[Events and Runners](runtime/events.md)** — supply `Args` when running Instructions from code.
