Cartographing Jetpack Compose: compiler and runtime
Tags: android, jetpackcompose, kotlin
Published: 2021-05-09 17:47:59

Jetpack Compose is expected to become the preferred ui toolkit for Android and perhaps Kotlin-based Desktop apps. In several articles I have demonstrated how to use it. This one and its follow-ups will contain a more exploratory approach. 

Curious? Read on.

As of May 2021 Jetpack Compose consists of six broad *areas*:

- `compose.compiler` transforms `@Composable` functions and enables optimizations with a Kotlin compiler plugin
- `compose.runtime` provides the fundamental building blocks of Compose's programming model and state management, as well as the core runtime for the Compose Compiler Plugin to target
- `compose.foundation` provides basic ingredients for Compose applications
- `compose.ui` contains the fundamental components of a composable UI needed to interact with the device, including layout, drawing, and input
- `compose.animation` helps building, well, animations
- `compose.material` provides ready to use Material Design components

Have you noticed that I listed those areas in a specific order? While you can easily write wonderful Compose apps that do not use *animation* or *material* you will almost certainly need *runtime* and *foundation*. How about the first one, *compiler*?

## androidx.compose.compiler

Well, while it is of utmost importance to get the machinery going, you do not need to include it in your *build.gradle* file. Let's do it anyway, so that we can peek inside a little:

```groovy
implementation "androidx.compose.compiler:compiler:$compose_version"
```

![A look into the Compose Compiler](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l08j4mz44tur1bizxz9n.png)
 
Doesn't look like we would want to invoke any of these manually, right? 🤣 

Please recall: while (besides being annotated with `@Composable`) composables look like ordinary Kotlin functions, they are heavily processed during compile time.

```kotlin
fun test() = ""

class MainActivity : ComponentActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val a = ::test
    println(a)
```

prints

```
I/System.out: function test (Kotlin reflection is not available)
```

On the other hand function references of `@Composable` functions are not currently supported.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rnkd3mndqjpobq2crr63.png)
 
Another important thing to recall is that `@Composable` invocations can only happen from the context of a `@Composable` function.

![An error message regarding the invocation of a composable function](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e0j78kkdcnzolxi9d3nk.png)
 
Talking about `@Composable` inevitably brings us to the second area, as the annotation is located in package `androidx.compose.runtime`. 

## androidx.compose.runtime

As of May 2021 its description is rather sparse. We have 14 interfaces with interesting names like [Applier](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Applier.kt;l=33?q=Applier&sq=&ss=androidx), [Composer](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt;l=307?q=Composer&sq=&ss=androidx), [Composition](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composition.kt;l=33?q=Composition&sq=&ss=androidx) and `State`. And 12 classes, among them [Recomposer](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Recomposer.kt;l=104?q=Recomposer&sq=) and [Updater](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt;l=3047?q=Updater&sq=&ss=androidx). One enum (`Recomposer.State`) and 14 annotations. 

For example, `@Stable`

> is used to communicate some guarantees to the compose compiler
> about how a certain type or function will behave.

And `NonRestartableComposable`

> can be applied to Composable functions in order to prevent code
> from being generated which allow this function's execution to be
> skipped or restarted.

Now, which of these are parts of the Compose clockwork, and which will we be using in our apps? 

Assume, at some point you are invoking `androidx.compose.material.Text("Hello Compose")`. The resulting call chain has quite a few steps, among them are `BasicText()` and `CoreText()`. Both reside in `androidx.compose.foundation.text`. `CoreText()`, by the way, has an `internal` modifier. More importantly, it invokes yet another composable, `Layout()` in package `androidx.compose.ui.layout`.

The docs say:

> `Layout` is the main core component for layout. It can be used
> to measure and position zero or more layout children.
>
> The measurement, layout and intrinsic measurement behaviours of
> this layout will be defined by the `measurePolicy` instance. See
> `MeasurePolicy` for more details.
>
> For a composable able to define its content according to the
> incoming constraints, see
> `androidx.compose.foundation.layout.BoxWithConstraints`.

Let's peek inside [Layout.kt](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/Layout.kt;l=67?q=androidx.compose.ui.layout.Layout&sq=&ss=androidx):

![The Layout() composable](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qj4ftev9j8mo8g7cp19c.png)
 
With the invocation of `ComposeNode` we make our way back to package `androidx.compose.runtime`. The docs say:

> Emits a node into the composition of type `T`. Nodes emitted
> inside of content will become children of the emitted node.

Again, [some code](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composables.kt;l=204?q=ComposeNode&sq=&ss=androidx):

![The ComposeNode() composable](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5vea2ma16l77gqrdwwpy.png)
 
Without going into too much detail we see heavy use of `currentComposer`, which is an instance of the `Composer` interface. It is based upon the concept of nodes. `Updater` is

> A helper receiver scope class used by `ComposeNode` to help 
> write code to initialized and update a node.

## Take aways

At this point you might recall the title of this article, *Cartographing Jetpack Compose*, and ask yourself if we still are on track. We are, as we now have quite some understanding of the innards of Compose. We have seen that invoking composables leeds to building and updating node-based structures. How they become - or lead to - what we see on screen is another interesting story I may be telling later. 

In this episode we have cartographed two areas, *compose.compiler* and *compose.runtime*. The first one is very important, yet uninteresting from an apps' perspective. The latter one both drives the (re-)composition of the ui and offers key elements like `@Composable` and `Layout`. We have already seen *foundation* briefly. Please stay tuned for a more detailed look.

Did you like this article? Please share your thoughts in the comments.

---

[Screen orientation in Jetpack Compose (4 Part Series)](https://dev.to/tkuenneth/series/11800)
[Drawing and painting in Jetpack Compose (3 Part Series)](https://dev.to/tkuenneth/series/10525)
[On (de)composing action bars (3 Part Series)](https://dev.to/tkuenneth/series/11418)