> ## Documentation Index
> Fetch the complete documentation index at: https://abxbus.archivebox.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Return Value Handling

> Define typed handler returns and collect results from one emitted event.

Handler return values are captured in `EventResult` records and can be consumed as a single value or aggregated across handlers.

Repository example files:

* [`examples/simple.py`](https://github.com/ArchiveBox/abxbus/blob/main/examples/simple.py)
* [`abxbus-ts/examples/simple.ts`](https://github.com/ArchiveBox/abxbus/blob/main/abxbus-ts/examples/simple.ts)
* [`abxbus-rust/tests/test_event_result.rs`](https://github.com/ArchiveBox/abxbus/blob/main/abxbus-rust/tests/test_event_result.rs)

## Typed return values

Use the event result type to enforce return typing across handlers.

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from abxbus import BaseEvent, EventBus

    class DoMathEvent(BaseEvent[int]):
        a: int
        b: int

    def add(event: DoMathEvent) -> int:
        return event.a + event.b

    bus = EventBus('AppBus')
    bus.on(DoMathEvent, add)

    event = await bus.emit(DoMathEvent(a=2, b=3)).now()
    result = await event.event_result()
    ```
  </Tab>

  <Tab title="TypeScript">
    ```ts theme={null}
    import { BaseEvent, EventBus } from 'abxbus'
    import { z } from 'zod'

    const DoMathEvent = BaseEvent.extend('DoMathEvent', {
      a: z.number(),
      b: z.number(),
      event_result_type: z.number(),
    })

    const bus = new EventBus('AppBus')
    bus.on(DoMathEvent, (event) => event.a + event.b)

    const event = bus.emit(DoMathEvent({ a: 2, b: 3 }))
    await event.now()
    const result = await event.eventResult()
    ```
  </Tab>

  <Tab title="Rust">
    ```rust theme={null}
    use abxbus::{
        event,
        event_bus::EventBus,
        BaseEvent,
    };
    use futures::executor::block_on;

    event! {
        struct DoMathEvent {
            a: i64,
            b: i64,
            event_result_type: i64,
        }
    }

    let bus = EventBus::new(Some("AppBus".to_string()));
    bus.on(DoMathEvent, |event: DoMathEvent| async move {
        Ok(event.a + event.b)
    });

    let event = bus.emit(DoMathEvent { a: 2, b: 3, ..Default::default() });
    let result = block_on(event.event_result())?;
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    type DoMathEvent struct {
    	A int `json:"a"`
    	B int `json:"b"`
    }

    bus := abxbus.NewEventBus("AppBus", nil)
    bus.On(func(event DoMathEvent) (int, error) {
    	return event.A + event.B, nil
    })

    emitted := bus.Emit(DoMathEvent{A: 2, B: 3})
    result, err := emitted.EventResult()
    ```
  </Tab>
</Tabs>

## Aggregating multiple handler results

When multiple handlers respond to the same event, collect all successful values with the list helpers.

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    event = await bus.emit(GetConfigEvent()).now()
    values = await event.event_results_list(raise_if_any=False, raise_if_none=False)
    ```
  </Tab>

  <Tab title="TypeScript">
    ```ts theme={null}
    const event = bus.emit(GetConfigEvent({}))
    const values = await event.eventResultsList({ raise_if_any: false, raise_if_none: false })
    ```
  </Tab>

  <Tab title="Rust">
    ```rust theme={null}
    use abxbus::{
        base_event::EventResultOptions,
        event,
        event_bus::EventBus,
        BaseEvent,
    };
    use futures::executor::block_on;
    use serde_json::json;

    event! {
        struct GetConfigEvent {
            event_result_type: serde_json::Value,
        }
    }

    let bus = EventBus::new(Some("ConfigBus".to_string()));

    bus.on(GetConfigEvent, |_event: GetConfigEvent| async move {
        Ok(json!({"debug": true, "port": 8080}))
    });
    bus.on(GetConfigEvent, |_event: GetConfigEvent| async move {
        Ok(json!({"debug": false, "timeout": 30}))
    });

    let event = bus.emit(GetConfigEvent { ..Default::default() });
    let values = block_on(event.event_results_list_with_options(EventResultOptions {
        raise_if_any: false,
        raise_if_none: false,
        ..EventResultOptions::default()
    }))?;
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    type GetConfigEvent struct{}

    event := bus.Emit(GetConfigEvent{})
    values, err := event.EventResultsList(
    	&abxbus.EventResultOptions{RaiseIfAny: false, RaiseIfNone: false},
    )
    ```
  </Tab>
</Tabs>

## Result list options

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    await event.event_results_list(raise_if_any=False, raise_if_none=False)
    await event.event_results_list(include=lambda result, _: isinstance(result, dict), raise_if_any=False)
    completed = await event.wait(timeout=0.25)
    await completed.event_results_list()
    ```
  </Tab>

  <Tab title="TypeScript">
    ```ts theme={null}
    await event.eventResultsList({ raise_if_any: false, raise_if_none: false })
    await event.eventResultsList({ include: (result) => typeof result === 'object', raise_if_any: false })
    await event.wait({ timeout: 0.25 }).eventResultsList()
    ```
  </Tab>

  <Tab title="Rust">
    ```rust theme={null}
    use abxbus::base_event::{EventResultOptions, EventWaitOptions};

    event.event_results_list_with_options(EventResultOptions {
        raise_if_any: false,
        raise_if_none: false,
        ..EventResultOptions::default()
    }).await?;
    let completed = event.wait_with_options(EventWaitOptions {
        timeout: Some(0.25),
        ..EventWaitOptions::default()
    }).await?;
    completed.event_results_list().await?;
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    event.EventResultsList(&abxbus.EventResultOptions{
    	RaiseIfAny: false,
    	RaiseIfNone: false,
    })
    timeout := 0.25
    completed, err := event.Wait(&abxbus.EventWaitOptions{Timeout: &timeout})
    if err != nil {
    	return err
    }
    completed.EventResultsList()
    ```
  </Tab>
</Tabs>

* Default options are `raise_if_any=true` and `raise_if_none=false` in every runtime.
* `raise_if_any`: raise if any handler ended with an error.
* `raise_if_none`: raise only when no handlers returned a valid value after filtering; it does not raise just because one handler returned `None`/`null`/`undefined`.
* If every handler errors, only `raise_if_any=false` plus `raise_if_none=false` suppresses the error and returns no value/empty list; every other option combination raises.
* A single handler error is raised as that error; multiple handler errors are raised as an aggregate/exception-group shape.
* Default filtering includes only completed, successful, non-empty scalar/object/list values and excludes forwarded `BaseEvent` returns.
* Go accepts no args for defaults (`event.EventResult()` / `event.EventResultsList()`) and a single `nil` options value is equivalent to defaults.

## Per-handler inspection

All runtimes keep per-handler result metadata in addition to the aggregate result helpers.

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    by_name = {result.handler_name: result.result for result in event.event_results.values()}
    ```
  </Tab>

  <Tab title="TypeScript">
    ```ts theme={null}
    const byHandler = event.event_results
    ```
  </Tab>

  <Tab title="Rust">
    ```rust theme={null}
    let by_name: std::collections::HashMap<_, _> = event
        .event_results
        .read()
        .values()
        .map(|result| (result.handler.handler_name.clone(), result.result.clone()))
        .collect();
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    byName := map[string]any{}
    for _, result := range event.EventResults {
    	byName[result.HandlerName] = result.Result
    }
    ```
  </Tab>
</Tabs>
