Compose Runtime/Compiler-plugin (not Compose UI) & workflow-kotlin #272
-
I’d like to hear your thoughts on Compose Runtime/Compiler-plugin and the workflow framework. Compose’s tree managing features seem to be a perfect fit for a workflow runtime that manages a tree of workflows. |
Beta Was this translation helpful? Give feedback.
Replies: 9 comments 3 replies
-
We’ve looked at this from two angles. Keeping the fundamental workflow shape (state machine where each workflow is built around a single state value and state transitions), and from the other side: trying to solve the same problems workflow was built to solve completely from scratch, writing minimal code to make it easier to use from compose. Keep Workflow ShapeI’ve prototyped using local delegate properties to store state, which lets workflows be written as single functions. I’ve done this with custom stuff, as well as using compose’s states and snapshots machinery. It’s really ergonomic, but since workflow doesn’t assume everything’s being controlled by frames, there’s a lot of open questions about how to scope non-atomic state changes that are performed off the main thread. Note that this doesn’t actually require using Complete RewriteI agree. I’ve been thinking about what this could look like. As for shape, one possibility is that Workflow becomes a simplified Composition that doesn’t emit anything, and just basically builds a tree of StateFlows. One tricky bit with this approach is that such a composition would be incompatible with a UI composition, but there’s no way to enforce that at compile time so it would be endlessly confusing trying to determine which composable functions could be called from what contexts. This would be great if Compose was more type safe wrt Applier type. Another, much riskier, much riskier idea that i had was to wrap a UI composition in one that emitted workflow sessions as nodes, and any UI emissions from a child workflow would be effectively recorded and then could be played back later in the UI composition, but i wasn’t able to get that working when i tried, and i think it might not work for subtle reasons. |
Beta Was this translation helpful? Give feedback.
-
I am exploring Compose runtime integration with the Workflow runtime integration. I am leaning heavily in preferring the "Keep Workflow Shape" option here as I am approaching this from the perspective not necessarily of app developer ergonomics, but assuming the current Workflow ergonomics and their tradeoffs for providing explicitness are worth it (and the migration burden is not). What we want to accomplish with Compose in the runtime is to optimize what parts of the tree need to be re-rendered/re-composed. My WIP is here: #814 @zach-klippenstein I would definitely appreciate your feedback and you might be able to see something i'm completely missing as to why this won't work from the Compose side of things. The key choices would be:
|
Beta Was this translation helpful? Give feedback.
-
Currently dealing with runtime clashes finding the |
Beta Was this translation helpful? Give feedback.
-
I think mirroring the core API will be necessary to some degree between Compose/no Compose runtimes and this will definitely make migration more straightforward and possible to be partial. New approach: #823 |
Beta Was this translation helpful? Give feedback.
-
Stuck again on method overloading not resolving. Will need to try and step away come back at this again soon: #823 |
Beta Was this translation helpful? Give feedback.
-
Continuing diary: The idea is be to let the Workflow runtime manage the coroutine scopes for Workers and child workflows and keep action processing in the Runner as it is and solely use a Compose runtime driven by molecule to produce the renderings and broadcast the frames for that compose runtime whenever the WOrkflow runtime decides it wants to render. The problem is I provided a default implementation of the @composable version of render and it keeps getting resolved at runtime rather than the overloaded versions even though the Workflow instance is correct when debugging through. I have a hunch it might have to do with the @composable lambda I'm using to hoist the Rendering back up to the root (so that each @composable Render() can return Unit and have its own recompose scope.) I recognize this may not work as maintaining these separate runtimes could lead to a lot of timing collisions? But I thought this would be the least impactful way to use the Recomposer to optimize rendering. We would then move gracefully towards a more comprehensive Composey API. |
Beta Was this translation helpful? Give feedback.
-
Got this running here after more discussion with Zach: #824. Still TODO: Snapshotting, and how to freeze after a render pass when its done via Compose. |
Beta Was this translation helpful? Give feedback.
-
#824 has been updated to isolate the compose optimizations so its an optional plugin to the runtime rather than bloating the core for existing users. |
Beta Was this translation helpful? Give feedback.
-
Is the intention here to create a "static" tree with dynamic renderings? Something similar to what would happen if each node provided a StateFlow so that the entire tree of renderings didnt have to be refreshed in order to refresh a single leaf? |
Beta Was this translation helpful? Give feedback.
We’ve looked at this from two angles. Keeping the fundamental workflow shape (state machine where each workflow is built around a single state value and state transitions), and from the other side: trying to solve the same problems workflow was built to solve completely from scratch, writing minimal code to make it easier to use from compose.
Keep Workflow Shape
I’ve prototyped using local delegate properties to store state, which lets workflows be written as single functions. I’ve done this with custom stuff, as well as using compose’s states and snapshots machinery. It’s really ergonomic, but since workflow doesn’t assume everything’s being controlled by frames, there’s a lot of open qu…