It would be convenient if we had a single array class instead of two (Array and AsyncArray).
Array exists because users expect an object that has blocking IO methods. AsyncArray exists because under the hood, those blocking IO methods need to use async routines. Lurking in the background is the sync function, which we use to run coroutines in an event loop running in a zarr-owned daemon thread.
schematically, this is what we have today:
class AsyncArray:
async def do_stuff() -> coroutine[result]:
# actually do stuff
class Array:
_async_array: AsyncArray
def do_stuff() -> result:
return sync(self._async_array.do_stuff())
An alternative approach:
class Runner(Protocol):
def run(coro: Awaitable[T]) -> T: ...
class DefaultRunner:
def run(coro: Awaitable[T]) -> T:
return sync(coro)
class Array:
_runner: Runner
def __init__(self, runner: Runner | None = None) -> None:
if runner is None: runner = DefaultRunner()
self._runner = runner
def do_stuff_async() -> coroutine[result]:
# actually do stuff
def do_stuff() -> result:
return self._runner.run(self.do_stuff_async())
As long as python async works the way it does, we will be dealing with 2 versions of the same function. so IMO we should accept that, and endeavor to put the two versions as close together as possible in the codebase. This proposal achieves that. And we get to eventually remove an entire class! (NOTE! I'm not saying we will do that immediately. the goal of removing dead code is not a promise to immediately do breaking changes).
It would be convenient if we had a single array class instead of two (
ArrayandAsyncArray).Arrayexists because users expect an object that has blocking IO methods.AsyncArrayexists because under the hood, those blocking IO methods need to use async routines. Lurking in the background is thesyncfunction, which we use to run coroutines in an event loop running in a zarr-owned daemon thread.schematically, this is what we have today:
An alternative approach:
As long as python async works the way it does, we will be dealing with 2 versions of the same function. so IMO we should accept that, and endeavor to put the two versions as close together as possible in the codebase. This proposal achieves that. And we get to eventually remove an entire class! (NOTE! I'm not saying we will do that immediately. the goal of removing dead code is not a promise to immediately do breaking changes).