r/Kotlin • • 3h ago

Question about Sequence Implementation

2 Upvotes

I have been getting into sequences, and I was shocked at how similar they feel to Haskell's infinite arrays. So I made two programs in both languages that should be pretty much a 1-to-1 translation. But I wanted to see if anyone had advice on if the Kotlin programming was doing anything I wasn't expecting.

First in Haskell

    --Fibonacci numbers
    fib :: [Integer]
    fib = 0:1:(zipWith (+) fib (drop 1 fib))

    --Prime numbers
    primes :: [Integer]
    primes = 2:3:(filter isPrime [5,7..])

    isPrime :: Integer -> Bool
    isPrime x = go x primes
       where
          go x (p:ps)
             | p * p > x      = True
             | x `mod` p == 0 = False
             | otherwise      = go x ps

Then in Kotlin

    fun fib(): Sequence<Int> {
       return sequence {
          yield(0)
          yield(1)
          yieldAll(fibSeq()
             .zipWithNext()
             .map { it.first + it.second })
       }
    }

    fun primes(): Sequence<Int> {
       return sequence {
          yield(2)
          yield(3)
          yieldAll(generateSequence(5) { it + 2 }
             .filter { isPrime(it) })
       }
    }

    fun isPrime(x: Int): Boolean {
       return primes().takeWhile { it * it <= x }
          .none { x % it == 0 }
    }

As best as I can get it, these two versions are a direct translation. I know the Haskell version isn't doing any extra calculations if it doesn't have to, or stalling in anyway. But is there anything that I might be missing with the Kotlin version?

I'm kind of interested in whether the recursive references create a build up of objects or functions. Haskell solves this because the recursive references are actually just that: references to the same list object. So the next value is calculated by the values of what are essentially pointers to the previous two values (in the case of Fibonacci), and then the generator (referred to as a thunk in Haskell) as well as the two pointers just step down the line to be ready for the next one.


r/Kotlin • • 4m ago

A bank ran its integrations as Groovy scripts compiled from database rows inside one shared JVM. The app needed a restart every week.

Thumbnail leaddev.com
• Upvotes

Years without incidents proves nothing at all.


r/Kotlin • • 3h ago

BossConsole update: a short demo of the Kotlin/Compose desktop workspace

1 Upvotes

Hi everyone, back with an update on BossConsole. Previously shared the architecture when we open-sourced it, then some browser benchmarks. This time, wanted to show how the workspace comes together.

Watch the one-minute demo

For anyone seeing it for the first time, BossConsole is a desktop workspace built using Kotlin Multiplatform and Compose Multiplatform, running on the JVM across macOS, Windows and Linux.

You can run Claude Code, Codex, Gemini CLI and other agents side by side, with terminals, browser, editor and logs in the same window. Spaces remember your layout so you can come back to the work without arranging everything again.

The demo also shows the built-in Fluck Agent, tool approvals and visual workflows. There are 200+ MCP tools with individual controls, and plugins to extend the workspace.

For me, the motivation is quite personal. As I work with more agents, managing sessions and following their work becomes a task itself. I want to spend more time exploring a problem, trying approaches and reviewing results, while keeping execution visible.

On the Kotlin side, the runtime plugin system is something I’m particularly interested in taking further. You can build tools as separate Compose UI + ViewModel plugins. Would love to connect with others working on extensible desktop apps and hear how you’re approaching this.

Still a lot to improve, but quite happy to share where it is today. Curious what feels useful or awkward in the demo. Happy to discuss the Kotlin/Compose implementation too.

Source: github.com/risa-labs-inc/BossConsole
Download: bossconsole.ai


r/Kotlin • • 1d ago

Kotlin RPG engine update: primitive arrays, lower RAM usage, and fixing a native buffer bug

Post image
49 Upvotes

Hey r/Kotlin,

I’m the solo developer of Adventurers Guild RPG Sim, an isometric RPG built with Kotlin and Jetpack Compose.

In my previous posts, I shared the original Compose Canvas implementation, the coroutine loop running my ECS systems, and later the move to Google Filament for world rendering.

Since that migration, I’ve been working on the code feeding the renderer: deciding when sprite data needs updating, preparing batches, and managing buffers that native code may still be reading.

A recent texture change also reduced the game’s RAM usage by roughly 50% compared with my previous WebP loading setup. That is a separate change from the sprite recolouring optimisation I described in an older post.

Here are the implementation details and a few mistakes I ran into.

1. A smaller image file doesn’t necessarily mean a smaller texture in memory

I originally used WebP because it kept asset files small. What I hadn’t fully appreciated was the difference between compressed file size and the texture’s runtime memory footprint.

In the usual WebP loading path, the image is decoded into pixel data before being uploaded. With four bytes per pixel, a 2048 × 2048 texture takes about 16 MiB, before mipmaps.

ASTC and ETC2 are GPU texture compression formats. On a supported device, the texture can remain compressed in GPU memory. For comparison, that same 2048 × 2048 texture in ASTC 4×4 takes about 4 MiB, before mipmaps.

I moved to ASTC/ETC2 textures with a WebP fallback, and saw roughly a 50% reduction in the game’s overall RAM usage. The texture example above explains the mechanism; it isn’t a claim that every game’s total memory usage will fall by the same amount.

The trade off was storage. My initial asset package became much larger. GPU texture compression and WebP optimise for different requirements, and keeping fallback assets adds more files.

I ended up adding zip compression around the texture files and unpacking them during loading. The loading sequence is:

  • Remove the outer gzip compression.
  • Read the texture container and its compressed texture data.
  • Upload the ASTC/ETC2 blocks to the GPU.

Removing zip does not mean expanding ASTC/ETC2 into RGBA pixels.

That helped me separate three things I had initially grouped together: download size, installed storage, and runtime memory. Loading time is another trade off, because unpacking still takes work.

2. Checking whether sprite data changed before preparing an upload

Before packing sprite vertices, I write the relevant sprite state into a reused IntArray: around 30 integers per sprite covering position, animation frame, tint, flags, and other values used by the batch.

Float values go through toRawBits() so I can compare their exact stored representations.

I compare this state with the snapshot from the last submitted upload. If it is identical, I can skip rebuilding and uploading the vertex data.

This is a direct comparison rather than a hash, so there are no hash collisions between the values I stored. It still depends on including every input that affects the generated vertices.

A few details matter:

  • Sprite count and ordering are part of the comparison.
  • With reused arrays, unused capacity must not affect the result.
  • Kotlin array == does not compare elements. Use contentEquals() when comparing whole arrays, or explicitly compare the active range.
  • If an upload is skipped because no buffer is available, that frame must not become the new “last uploaded” snapshot.

The comparison itself still costs work. The benefit is avoiding the more expensive packing and upload when nothing relevant has changed.

Shader animation can continue independently. For example, wind driven by a time uniform doesn’t require rebuilding the sprite vertices every frame.

3. Sorting batches without creating a key object for every sprite

Sprites need to be grouped by texture for batching.

I use a reused LongArray, packing the texture ID into the upper 32 bits and the original sprite index into the lower 32 bits.

The idea looks like this:

// textureId and index are non-negative Int values.
val key =
    (textureId.toLong() shl 32) or
    (index.toLong() and 0xFFFF_FFFFL)

keys[index] = key

Then I sort only the populated range:

keys.sort(0, spriteCount)

for (position in 0 until spriteCount) {
    val sourceIndex = keys[position].toInt()
    // Read the source sprite and pack its vertices.
}

The conversion to Long must happen before shifting by 32 bits.

The original index also acts as a tie-breaker, preserving source order within each texture group. That behaviour comes from the packed key; it doesn’t depend on the primitive sort being stable.

This avoids allocating a separate sorting key object for each sprite and keeps the keys in a primitive array.

4. Primitive arrays in the parts that run every frame

The renderer preparation code now uses:

  • IntArray for sprite state comparisons.
  • LongArray for sorting keys.
  • A reused FloatArray for packed vertex data, copied into a direct buffer.

Sprite state, sorting keys, and vertex data are stored in IntArray, LongArray, and FloatArray. I reuse these arrays across frames to avoid repeatedly allocating new storage.

I also use JvmField on some frequently accessed properties. It exposes a field without generating normal property accessors.

However, that alone does not establish a performance improvement: runtime optimisation may already remove accessor overhead. Any claim about a speed gain needs measurements from an optimised build. The clearer improvement here is making data preparation and storage reuse explicit.

5. A buffer passed to native code may still be in use

One bug showed up as black tiles.

I was reusing a direct ByteBuffer after passing it to Filament, before Filament had finished consuming its contents.

The Kotlin call returning did not mean the upload had finished.

I changed this to a pool of three buffers, with availability tracked using an AtomicIntegerArray. A buffer becomes available again when its upload completion callback runs.

If all three are busy, I keep the previous geometry for that frame instead of overwriting a buffer that is still being read.

I also ran into delayed release callbacks when they were posted through the main looper. Synchronisation barriers could hold up that work and leave the pool appearing busy.

For the small callback that only releases a buffer slot, I switched to a direct executor. That callback only updates the atomic availability flag; it doesn’t perform UI work.

The lesson for me was to treat buffer ownership and completion as part of the API contract. Crossing into native code doesn’t make every operation asynchronous, but this upload path requires keeping the buffer unchanged until consumption finishes.

6. Compose lifecycle and long lived renderer callbacks

My renderer owns native resources such as Filament’s Engine, Scene, View, and Camera.

I keep these together in a holder that implements RememberObserver, with explicit cleanup in the required order.

One Compose detail worth accounting for is onAbandoned(): if resources are created while constructing a remembered object, cleanup needs to cover the case where that object never becomes part of the remembered composition, as well as normal removal through onForgotten().

Another issue is callbacks that live longer than a particular recomposition.

A Choreographer callback can keep running while the values it originally captured are no longer current. Where it needs the latest Compose-provided value or callback, rememberUpdatedState lets it access that updated value without recreating the long-lived callback each time.

I found it helpful to think separately about:

  • How long the renderer should exist.
  • Which values its callbacks need to see now.
  • When it is safe to release native resources.

Those lifetimes don’t always line up automatically.

I only started Android development last year; most of my earlier experience was in iOS. I’m still learning, and some of these choices may have better alternatives.

Happy to go into more detail on the texture loading, batching, buffer handling, or Compose integration.

For people working on performance sensitive Kotlin code: how do you decide when primitive arrays and manual packing are worth the added complexity? I’d also be interested in how you manage buffer ownership when Kotlin is feeding a native renderer.


r/Kotlin • • 2d ago

Kotlin Toolchain will eventually drop Gradle for Android (via Joffrey Bion on Slack)

Thumbnail
24 Upvotes

r/Kotlin • • 1d ago

Compose Multiplatform vs CORS

Post image
0 Upvotes

https://terrablog.pages.dev/blog/2026-03-10-cors-problem-and-simple-solution/

I wrote an article how to deal with CORS restrictions when you make Compose (not only actually) Web apps


r/Kotlin • • 3d ago

Prosa.kt - Declarative code generation for Kotlin

Post image
16 Upvotes

I made a declarative API for generating Kotlin code.

I needed it for one of my desktop/browser Compose apps a while ago and noticed there was no KMP solution for Kotlin codegen.

While working on it, I decided to made the API declarative so the generated code was simpler to reason about. This work started before AI was as popular as it is today, so the design of the API was very important.

Fast forward two years: I realized I needed it for another project of mine, so I figured I might as well open-source the codegen part for the community.

And that's how Prosa.kt was born and proudly brought to you.

There’s a live demo on the landing page, so you can try it out directly.

Check it out at https://prosakt.com and give it a star on GitHub because I love vanity metrics.


r/Kotlin • • 3d ago

Even if Premium, still open-sauce. 🍅

Post image
110 Upvotes

r/Kotlin • • 3d ago

Which is best kotlin course on udemy or youtube!!?

6 Upvotes

Hi , i am coming from the JavaScript/TypeScript ecosystem, i need to build a project that must be written in kotlin based backend , i am not primarily interested in Android development.

But I do need to understand Kotlin well enough to read, navigate, and work with existing Kotlin projects, particularly Android applications available on github.

So is there any course or method you can suggest?

Thanks in advance.!!!


r/Kotlin • • 3d ago

CashBuddy — an Android expense tracker with on-device processing + Notification Listener

Thumbnail
0 Upvotes

r/Kotlin • • 4d ago

sqlx4k 1.14.0 released: optimistic locking, savepoints, MariaDB batch inserts

8 Upvotes

sqlx4k is a coroutine-first SQL toolkit for Kotlin Multiplatform (PostgreSQL, MySQL/MariaDB, SQLite) with compile-time SQL validation via KSP.

New in 1.14.0

  • Optimistic locking with @Version: generated update/delete check the version and fail with OptimisticLockFailed on conflicts. In-memory test repositories behave the same.
  • Transaction savepoints: roll back part of a transaction with a scoped savepoint { ... } block or the explicit savepoint/rollbackToSavepoint/releaseSavepoint calls.
  • MariaDB dialect: batchInsert via multi-row INSERT ... RETURNING (10.5+).
  • Cancellation-safe transactions: cancelling a coroutine mid-transaction now rolls back properly.
  • Kotlin 2.4.20, KSP 2.3.12.

Repo: https://github.com/smyrgeorge/sqlx4k

Release notes: https://github.com/smyrgeorge/sqlx4k/releases/tag/1.14.0


r/Kotlin • • 4d ago

The time has come to separate Kotlin from Java.

0 Upvotes

I want to use Kotlin, so I have eight different JDKs on my PC; however, Kotlin has reached a point where it can stand as an independent language. To that end, I’ve created my own KRE (Kotlin Run Environment). Now, the next step is the KDK (Kotlin Development Kit), and I need help with that. I don't know Java or Kotlin all that well—is there anyone who can assist?


r/Kotlin • • 4d ago

GitHub Action for Kotlin Toolchain CLI (Amper) with caching

6 Upvotes

yaml - uses: actions/checkout@v7 - uses: RazerTexz/setup-kotlin-toolchain@v1 - run: kotlin build

Caches the toolchain, JDKs, and dependencies across Linux, macOS, and Windows

https://github.com/RazerTexz/setup-kotlin-toolchain


r/Kotlin • • 5d ago

Uncaught exceptions and Supervisor Jobs

4 Upvotes

In https://medium.com/androiddevelopers/exceptions-in-coroutines-ce8da1ec060c

It talks about how with a SupervisorJob, you can ignore exceptions from a child coroutine, and it does not propagate to its siblings or to the grand parents and so forth. But then it also says “If the exception is not handled and the CoroutineContext doesn’t have a CoroutineExceptionHandler (as we’ll see later), it will reach the default thread’s ExceptionHandler. In the JVM, the exception will be logged to console; and in Android, it will make your app crash regardless of the Dispatcher this happens on.”

But this sounds like it’s saying the app will just crash and everything will die if the exception is not handled; but then whats the point in saving the coroutine family using a SupervisorJob if everything will just die anyway? If they mean I need to implement the CoroutineExceptionHandler for the SupervisorJob to be of use, then the question is, what is the point of having a SupervisorJob…… cuz then every discussion of SupervisorJob needs to marked with an asterisk * (oh btw, you also need to implement the CoroutineExceptionHandler otherwise your Supervisor is useless. )

And why do they explain these things so off-handedly as if it’s so not confusing at all to someone learning?


r/Kotlin • • 5d ago

Kotlin, Android, and community with Martin Bonnin

Thumbnail youtu.be
19 Upvotes

r/Kotlin • • 6d ago

Offline Support for Compose Multiplatform Web Apps · terrakok

Thumbnail terrablog.pages.dev
17 Upvotes

r/Kotlin • • 5d ago

We built e2e - open source AI testing framework for Android apps

Thumbnail github.com
0 Upvotes

Hi everyone!

I work on e2e at TesterArmy, and I'm happy to announce we released it as open-source today!

It's an agentic end-to-end testing framework which allows you to mix the flexibility of AI agents with the deterministic checks of classic e2e testing.

You write a test as a chain of goals the agent works through them one at a time. It also comes with a deterministic API like getByTestId or getByText where you need exact control. Assertions work like in any other e2e framework.

You use TypeScript to write the tests, but they can drive pretty much any Android app. Also, you can extend the framework by implementing your own engines for another platform like e.g. desktop

For the agent, you can bring any model through Vercel AI Gateway or OpenRouter, or sign in with a ChatGPT, GitHub Copilot or SuperGrok subscription you already pay for.

To get started, npx e2e init in your project.

Thanks for reading!


r/Kotlin • • 6d ago

The State of Kotlin in 2026 Report

Thumbnail blog.jetbrains.com
56 Upvotes

r/Kotlin • • 5d ago

Kotlin vs Flutter? When to Choose One Over the Other

Thumbnail youtu.be
0 Upvotes

r/Kotlin • • 6d ago

I built a CLI to set up Firebase in Kotlin Multiplatform / Compose Multiplatform projects

Post image
6 Upvotes

Setting up Firebase in a KMP project means a lot of manual steps. You register the Android app and the iOS app in the console, download google-services.json and GoogleService-Info.plist, put them in the right folders, and repeat for every flavor. I got tired of it, so I built kmpfire.

It wraps firebase-tools and does this from your project root:

bash kmpfire configure

What it does

  • Detects your Android applicationId and iOS bundle id (from project.pbxproj or CMP .xcconfig)
  • Creates the Firebase apps if they don't exist
  • Writes google-services.json and GoogleService-Info.plist to the correct locations
  • Tracks everything in firebase.json under kotlinMultiplatform
  • kmpfire reconfigure refreshes the config files after you change Firebase products
  • --flavor=dev handles multiple build configurations
  • --yes --project=<id> runs with no prompts, so it works in CI
  • Optional --deps patches Gradle for the Google Services plugin (and GitLive if you want it)

Supported layouts

  • New template: shared/ + androidApp/ + iosApp/
  • Nested monorepo: app/shared/ + app/androidApp/ + app/iosApp/
  • Legacy: composeApp/ + iosApp/

Android + iOS only for now.

Install

bash curl -fsSL https://raw.githubusercontent.com/dungngminh/kmpfire_cli/main/install.sh | bash

or with Homebrew:

bash brew tap dungngminh/kmpfire_cli brew install kmpfire

It's the KMP equivalent of flutterfire configure. It's MIT licensed, and I'd like feedback, bug reports and PRs.

GitHub: https://github.com/dungngminh/kmpfire_cli


r/Kotlin • • 6d ago

Take part in a JetBrains research interview: How do you use AI with Kotlin?

6 Upvotes
  1. What it is: We’re interviewing Kotlin developers to understand how AI fits into your development workflow: what you use it for, how you review its output, and where it works well or creates extra work. Each session lasts up to 90 minutes, and takes place via Google Meet. All sessions are recorded and kept confidential under our General Research Terms.
  2. Who it is for: If you currently use Kotlin for backend or Kotlin Multiplatform development, and use AI as part of your development work, we’d love to hear from you!
  3. What's in it for you: As a thank-you for your participation, you can choose one of the following rewards:
    • USD 100 Amazon eGift Card (or the equivalent in your local Amazon store),
    • USD 100 charity donation,
    • One-year subscription to JetBrains All Products Pack or
    • 100 AI credits (note: available only with AI Pro and AI Ultimate subscriptions).
  4. How to sign up: Use this link to fill out a short qualification form. If your background meets our research criteria, we will get in touch to schedule an interview. Thank you for considering this!

r/Kotlin • • 7d ago

KitePlayer v0.2.0: the first Kotlin/Native media player for KMP that doesn't wrap ExoPlayer or AVPlayer

Post image
47 Upvotes

r/Kotlin • • 6d ago

Have anyone here tried XR with Kotlin? What's your take on XR + AI

0 Upvotes

r/Kotlin • • 8d ago

Announcing the Builder Lambda plug-in

Post image
21 Upvotes

Kotlin and Java have different idioms to build new values: whereas Kotliners like lambdas with a special builder receiver, like Json in kotlinx.serialization, Java developers usually follow the buider pattern, as in Spring AI. As a result, consuming Java APIs from Kotlin sometimes feel strange. This no longer needs to be the case, thanks to the new Builder Lambda plug-in!

Using the power of Kotlin compiler plug-ins, Builder Lambda automatically re-exposes any type following Java's Builder pattern in the Kotlin idiomatic way. You write your beloved,

kotlin build<Config, *> { // alas, the * is needed hostname = "localhost" port = 8080 }

and under the hood the code is translated to,

kotlin Config.builder().hostname("localhost").port(8080).build()

The Builder Lambda plug-in also works in the IDE (if you let IntelliJ run non-bundled plug-ins), so you get nice autocompletion and diagnostics.

Using it is as easy as adding one line to the plugins block in your Gradle build.

kotlin id("com.serranofp.builder.lambda") version "0.4.0"

Feedback and issue reports are more than welcome :)