State Methods¶
Define helpers on State
classes that always operate on an instance.
- Instance call: uses that instance directly
- Class call: resolves an instance from context via
ctx.state(T)
This removes pitfalls of using @classmethod
, where calls on instances still receive the class.
Basic Usage¶
from haiway import State, ctx, statemethod
from typing import Callable
class Example(State):
do: Callable[[], str]
@statemethod
def do_stuff(self) -> str:
return self.do()
# Instance call: uses that instance
inst = Example(do=lambda: "from-instance")
assert inst.do_stuff() == "from-instance"
# Class call: resolves from current ctx
async def run() -> None:
async with ctx.scope("ex", Example(do=lambda: "from-ctx")):
assert Example.do_stuff() == "from-ctx"
Comparison with @classmethod
¶
class UsingClassmethod(State):
do: Callable[[], str]
@classmethod
def do_stuff(cls) -> str:
# cls is the class even when called via an instance
return ctx.state(cls).do()
inst = UsingClassmethod(do=lambda: "from-instance")
# This will NOT use `inst` — it still resolves via ctx.state(UsingClassmethod)
inst.do_stuff()
Use @statemethod
when you want class and instance calls to share a single, instance-based helper.
Best Practices¶
- Prefer plain instance methods when you never need class-level calls
- Use for service-like
State
classes that expose helpers through both class and instance - Keep helpers focused; inject dependencies via
State
attributes