Jetpack Compose and Data2viz

Jetpack Compose is a WIP new Kotlin-only UI toolkit that Google is developing for Android first. It was announced at Google I/O 2019.

As you can see, it’s called Jetpack Compose, not AndroidX Compose, so this is one of the clear signs multiplatform support is planned. I read several members of the team confirming it explicitly, and you can already see in the sources that the code is decoupled from Android, with Canvas being abstracted away for example.

One of the first things I noticed in @Composable annotated functions is that they don’t return what they are composing (no return type is specified, so it defaults to Unit). This led me to think that it may do allocations sparingly for performance reasons. After a discussion with one of the team members, I got confirmation, and what happens is that a mutable tree for the components to be drawn is passed instead, so no allocation for what didn’t change.

The way it works is similar to how functions with the suspend modifier pass a Continuation (done by kotlinc), but here, it is made by a compiler plugin wrote specifically for Jetpack Compose, which changes how @Composable annotated functions are compiled.

I’ve read (from Roman Elizarov IIRC) that it was likely that the compiler plugin for Jetpack Compose could be made quite generic to allow new use cases with similar techniques.

So, that brings several questions regarding Data2viz (numbered for easy referencing), especially considering the performance struggles with frequent allocations that the current implementation (as of early May of 2019) suffers from.

  1. Could Data2viz eventually rely on Jetpack Compose entirely? If so, that would imply a straightforward integration with all the platforms that are supported by Jetpack Compose, whether officially or not.

  2. If not, could a similar compiler plugin be used to allow under the hood performance optimizations where allocation would be reduced to a minimum thanks to compiler and implementation code solely controlling mutation?

  3. Do you think Jetpack Compose could be a Data2viz competitor, or make it easy for competitors to arise? If so, why? If not, why not? :upside_down_face:

1 Like

Thank you @louis.cad for this very detailed question.

I think that Compose comes naturally as a new pattern made possible by Kotlin. At the very beginning of Kotlin, Andrey Breslav explained how to write a DSL to create HTML. Later, it became Kotlinx.html which is a source of inspiration for data2viz. The main point of this pattern is to build the tree structure of a UI using the same tree of function calls. It’s easy to understand the code with this one-to-one mapping. Though, the goal is not to build a UI tree from code but also to bind or represent the state of the application. The significant step forward of Compose is how it uses the compiler plugin features of Kotlin to keep the link of what must be re-invoked when the Model changes. This approach generally uses some event mechanism to track changes at the lower level. It may work well for application UI.

Though, for data visualization, I think it won’t be efficient enough. In data-visualization, we need to display the state of a massive amount of objects. Think of this example. Using an event-based mechanism to update the position of thousands of points, would generate way too many events and function calls. In data-visualization, it’s better to update data state and the corresponding view using batch function calls. Also, the tree depth is smaller in dataviz. The compose pattern, as implemented in Google’s project, brings fewer benefits.

What makes more sense, is to extend Compose to web applications. HTML DOM trees can be very deep, and there is a significant need for these states management tools associated with a component approach. However, I think the goal, in that case, would be to use Kotlinx.html to manipulate the DOM and not abstract components rendered on a Canvas.

We must reduce the data2viz allocations you talk about to their minimum. However, this work is more about algorithm optimization and cleaning code. We have to get rid of Boxing/Unboxing problems. For some specific algorithms, we have to allocate only one time the needed structures and then reuse them.