Recent Posts
Archives

Posts Tagged ‘JetBrains’

PostHeaderIcon [KotlinConf2024] Kotlin Multiplatform Powers Google Workspace

At KotlinConf2024, Jason Parachoniak, a Google Workspace engineer, detailed Google’s shift from a Java-based multiplatform system to Kotlin Multiplatform (KMP), starting with Google Docs. For over a decade, Workspace has relied on shared code for consistency across platforms, like Gmail’s synchronization layer. Jason shared how KMP enhances this approach, leveraging Kotlin’s ecosystem for better performance and native interop. The talk highlighted lessons from the migration, focusing on build efficiency, runtime latency, and memory challenges, offering insights for large-scale KMP adoption.

Why Kotlin Multiplatform for Workspace

Google Workspace has long used multiplatform code to ensure consistency, such as identical email drafts across devices in Gmail or uniform document models in Docs. Jason explained that their Java-based system, using transpilers like J2ObjC, was effective but complex. KMP offers a modern alternative, allowing developers to write Kotlin code that compiles to native platforms, improving runtime performance and ecosystem integration. By targeting business logic—everything beyond the UI—Workspace ensures native-feel apps while sharing critical functionality, aligning with user expectations for productivity tools.

Google Docs: The Migration Testbed

The migration began with Google Docs, chosen for its heavily annotated codebase, which tracks build performance, latency, and memory usage. Jason described how Docs is rolling out on KMP, providing metrics to refine the Kotlin compiler and runtime. This controlled environment allowed Google to compare KMP against their legacy system, ensuring parity before expanding to other apps. Collaboration with JetBrains and the Android team has been key, with iterative improvements driven by real-world data, setting a foundation for broader Workspace adoption.

Tackling Build Performance

Build performance posed challenges, as Google’s Bazel-like system resembles clean builds, unlike Gradle’s incremental approach. Jason recounted a 10-minute build time increase after a Kotlin Native update optimized LLVM bitcode generation. While this improved binary size and speed, it slowed builds. Profiling revealed a slow LLVM pass, already fixed in a newer version. Google patched LLVM temporarily, reducing build times from 30 to 8 minutes, and is working with JetBrains to update Kotlin Native’s LLVM, prioritizing stability alongside the K2 compiler rollout.

Optimizing Runtime Latency

Runtime latency, critical for Workspace apps, required Kotlin Native garbage collection (GC) tweaks. Jason noted that JetBrains proactively adjusted GC before receiving Google’s metrics, but further heuristics were needed as latency issues emerged. String handling in the interop layer also caused bottlenecks, addressed with temporary workarounds. Google is designing long-term fixes with JetBrains, ensuring smooth performance across platforms. These efforts highlight KMP’s potential for high-performance apps, provided runtime challenges are systematically resolved through collaboration.

Addressing Memory Usage

Memory usage spikes were a surprise, particularly between iOS 15 and 16. Jason explained that iOS 16’s security-driven constant pool remapping marked Kotlin Native’s vtables as dirty, consuming megabytes of RAM. Google developed a heap dump tool generating HPROF files, compatible with IntelliJ’s Java heap analysis, to diagnose issues. This tool is being upstreamed to Kotlin Native’s runtime, enhancing debugging capabilities. These insights are guiding Google’s memory optimization strategy, ensuring KMP meets Workspace’s stringent performance requirements as the migration expands.

Links:

PostHeaderIcon [KotlinConf2025] Closing Panel

The concluding panel of KotlinConf2025 offered a vibrant and candid discussion, serving as the capstone to the conference. The diverse group of experts from JetBrains, Netflix, and Google engaged in a wide-ranging dialogue, reflecting on the state of Kotlin, its evolution, and the path forward. They provided a unique blend of perspectives, from language design and backend development to mobile application architecture and developer experience. The conversation was an unfiltered look into the challenges and opportunities facing the Kotlin community, touching on everything from compiler performance to the future of multiplatform development.

The Language and its Future

A central theme of the discussion was the ongoing development of the Kotlin language itself. The panel members, including Simon from the K2 compiler team and Michael from language design, shared insights into the rigorous process of evolving Kotlin. They addressed questions about new language features and the careful balance between adding functionality and maintaining simplicity. A notable point of contention and discussion was the topic of coroutines and the broader asynchronous programming landscape. The experts debated the best practices for managing concurrency and how Kotlin’s native features are designed to simplify these complex tasks. There was a consensus that while new features are exciting, the primary focus remains on stability, performance, and enhancing the developer experience.

The State of Multiplatform Development

The conversation naturally shifted to Kotlin Multiplatform (KMP), which has become a cornerstone of the Kotlin ecosystem. The panelists explored the challenges and successes of building applications that run seamlessly across different platforms. Representatives from companies like Netflix and AWS, who are using KMP for large-scale projects, shared their experiences. They discussed the complexities of managing shared codebases, ensuring consistent performance, and maintaining a robust build system. The experts emphasized that while KMP offers immense benefits in terms of code reuse, it also requires a thoughtful approach to architecture and toolchain management. The panel concluded that KMP is a powerful tool, but its success depends on careful planning and a deep understanding of the underlying platforms.

Community and Ecosystem

Beyond the technical discussions, the panel also reflected on the health and vibrancy of the Kotlin community. A developer advocate, SA, and others spoke about the importance of fostering an inclusive environment and the role of the community in shaping the language. They highlighted the value of feedback from developers and the critical role it plays in guiding the direction of the language and its tooling. The discussion also touched upon the broader ecosystem, including the various libraries and frameworks that have emerged to support Kotlin development. The panel’s enthusiasm for the community was palpable, and they expressed optimism about Kotlin’s continued growth and adoption in the years to come.

Links:

PostHeaderIcon [KotlinConf2024] Revamping Kotlin’s Type System: A Vision

At KotlinConf2024, Ross Tate, a programming language researcher, exposed critical flaws in Kotlin’s type system, including undecidability and unsoundness, which can crash compilers or misclassify types. Collaborating with the Kotlin team, he proposed pragmatic restrictions to ensure reliability and introduced extensions like categorized union types for error handling. Ross shared a long-term strategy to make type checking sound, decidable, and extensible, inviting developers to shape Kotlin’s future through feedback, balancing theory with practical needs.

Uncovering Type System Flaws

Kotlin’s type system, while powerful, is flawed. Ross revealed its undecidability, where subtyping questions can encode Turing machines, causing unpredictable compiler behavior. This stems from Java’s similar issues, as proven by Ru Gregori’s research. Unsoundness is equally concerning—Ross demonstrated a program tricking the compiler into treating an Int as a String using type projections and nulls. These flaws, also present in Java and Scala, undermine reliability, making robust type checking a priority for Kotlin’s evolution.

The Dangers of Unsound Programs

Unsoundness risks memory corruption. Ross presented a fast integer-to-string converter that, without proper checks, could introduce vulnerabilities. Initially, Kotlin’s compiler rejected it, as Int isn’t a subtype of String. However, adding a magic configuration with existential type projections bypassed this safeguard, fooling the compiler. Adapted from Java and Scala examples, this highlights a shared problem. Ross stressed that revamping Kotlin involves eliminating such unintentional backdoors, ensuring only explicit casts compromise safety, preserving developer trust.

Type Inference Challenges

Type inference, vital for Kotlin’s usability, struggles with decomposition. Ross showed a tree class for sorting adjectives, which type-checks when whole but fails when split into smaller parts. The compiler couldn’t infer the branch type B, violating the principle that breaking programs into smaller units shouldn’t break type checking. Co-variance adjustments revealed a principal type (Nothing), but Java’s undecidable subtyping influenced Kotlin’s conservative design. Ross aims to fix this, ensuring inference supports modular, predictable codebases.

Pragmatic Restrictions for Decidability

To address undecidability, Ross proposed separating interfaces into “shapes” (type constraints, like Comparable) and “materials” (data types, like function interfaces). Analyzing 135 million lines of Java code, he found all interfaces fit one category, making subtyping decidable in practice. By embedding this pattern into Kotlin, type checking becomes reliable and efficient, running in polynomial time. This separation also improves usability, as hovering over a variable avoids irrelevant types like Comparable<*>, aligning with developer expectations.

Categorized Union Types for Errors

Ross previewed categorized union types, restricted to prevent exponential type-checking costs. Types are grouped into categories (e.g., Null, Any, Error), allowing unions only across categories, like T | NoSuchValue. This enables distinguishing custom errors from null, as shown in a lastOrError function. Operators like !. (propagate error), !: (replace error), and !! (throw exception) mirror nullable syntax, simplifying libraries. Q&A clarified errors remain manipulable values, enhancing flexibility without compromising efficiency.

Enhancing Error Handling

The proposed error system differentiates errors (values) from exceptions (control flow). Error classes include a throw method for conversion to exceptions, while Throwable subclasses form distinct categories, enabling multi-catch via union types. A try-catch variant infers the union of thrown types, supporting exhaustive checks with Java’s typed exceptions. This design, inspired by Rust’s result pattern, balances explicit error handling with backward compatibility, addressing interoperability concerns raised in Q&A about Java’s ecosystem.

Shaping Kotlin’s Future

Ross emphasized that these changes are experimental, requiring prototypes, trials, and community input. Challenges like name resolution and method overloading need strategies, and features must cohere. He invited feedback via issue KT-68296, especially on error naming (e.g., “Error” vs. “Sentinel”) to avoid Java confusion. The talk underscored Kotlin’s shift toward optimizing its own experience, even at the cost of some Java interop precision, ensuring a reliable, extensible type system for future developers.

Links:

PostHeaderIcon [KotlinConf2024] DataFrame: Kotlin’s Dynamic Data Handling

At KotlinConf2024, Roman Belov, JetBrains’ Kotlin Moods group leader, showcased Kotlin DataFrame, a versatile library for managing flat and hierarchical data. Designed for general developers, not just data scientists, DataFrame handles CSV, JSON, and object subgraphs, enabling seamless data transformation and visualization. Roman demonstrated its integration with Kotlin Notebook for prototyping and a compiler plugin for dynamic type inference, using a KotlinConf app backend as an example. This talk highlighted how DataFrame empowers developers to build robust, interactive data pipelines.

DataFrame: A Versatile Data Structure

Kotlin DataFrame redefines data handling for Kotlin developers. Roman explained that, unlike traditional data classes, DataFrame supports dynamic column manipulation, akin to Excel tables. It can read, write, and transform data from formats like CSV or JSON, making it ideal for both analytics and general projects. For a KotlinConf app, DataFrame processed session data from a REST API, allowing developers to filter, sort, and pivot data effortlessly, providing a flexible alternative to rigid data class structures.

Prototyping with Kotlin Notebook

Kotlin Notebook, a plugin for IntelliJ IDEA Ultimate, enhances DataFrame’s prototyping capabilities. Roman demonstrated creating a scratch file to fetch session data via Ktor Client. The notebook’s auto-completion for dependencies, like Ktor or DataFrame, simplifies setup, downloading the latest versions from Maven Central. Interactive tables display hierarchical data, and each code fragment updates variable types, enabling rapid experimentation. This environment suits developers iterating on ideas, offering a low-friction way to test data transformations before production.

Dynamic Type Inference in Action

DataFrame’s compiler plugin, built for the K2 compiler, introduces on-the-fly type inference. Roman showed how it analyzes a DataFrame’s schema during execution, generating extension properties for columns. For example, accessing a title column in a sessions DataFrame feels like using a property, with auto-completion for column names and types. This eliminates manual schema definitions, streamlining data wrangling. Though experimental, the plugin cached schemas efficiently, ensuring performance, as seen when filtering multiplatform talk descriptions.

Handling Hierarchical Data

DataFrame excels with hierarchical structures, unlike flat data classes. Roman illustrated this with nested JSON from the KotlinConf API, converting categories into a DataFrame with grouped columns. Developers can navigate sub-DataFrames within cells, mirroring data class nesting. For instance, a category’s items array became a sub-DataFrame, accessible via intuitive APIs. This capability supports complex data like object subgraphs, enabling developers to transform and analyze nested structures without cumbersome manual mappings.

Building a KotlinConf Schedule

Roman walked through a practical example: creating a daily schedule for KotlinConf. Starting with session data, he converted startsAt strings to LocalDateTime, filtered out service sessions, and joined room IDs with room names from another DataFrame. Sorting by start time and pivoting by room produced a clean schedule, with nulls replaced by empty strings. The resulting HTML table, generated directly in the notebook, showcased DataFrame’s ability to transform REST API data into user-friendly outputs, all with concise, readable code.

Visualizing Data with Kandy

DataFrame integrates with Kandy, JetBrains’ visualization library, to create charts. Roman demonstrated analyzing GitHub commits from the Kotlin repository, grouping them by week to plot commit counts and average message lengths. The resulting chart revealed trends, like steady growth potentially tied to CI improvements. Kandy’s simple API, paired with DataFrame’s data manipulation, makes visualization accessible. Roman encouraged exploring Kandy’s website for examples, highlighting its role in turning raw data into actionable insights.

DataFrame in Production

Moving DataFrame to production is straightforward. Roman showed copying notebook code into IntelliJ’s EAP version, importing the generated schema to access columns as properties. The compiler plugin evolves schemas dynamically, supporting operations like adding a room column and using it immediately. This approach minimizes boilerplate, as seen when serializing a schedule to JSON. Though the plugin is experimental, its integration with K2 ensures reliability, making DataFrame a practical choice for building scalable backend systems, from APIs to data pipelines.

Links:

PostHeaderIcon [KotlinConf2024] The Best Programmer I Know: Insights from KotlinConf2024

At KotlinConf2024, Daniel Terhorst-North shared a heartfelt reflection on the traits of exceptional programmers, drawing from his 30-year career and a colleague who embodies these qualities. Without a formal degree, this programmer excels by starting tasks, prioritizing outcomes, simplifying solutions, choosing tools wisely, and fostering team growth. Daniel’s narrative, blending personal anecdotes and practical advice, inspires developers to cultivate curiosity, resilience, and empathy while building impactful software.

Starting with Action

Great programmers dive into tasks without hesitation. Daniel recounted how his colleague tackles projects by starting anywhere, embracing the unknown. This “just start” mindset counters procrastination, which Daniel admits to masking as research. By iterating rapidly—trying, failing, and learning—programmers overcome perfectionism and ego. Daniel likened progress to navigating a grid city, moving stoplight to stoplight, accepting delays as part of the journey, ensuring steady advancement toward solutions.

Prioritizing Outcomes Over Code

Building products, not just code, defines effective programming. Daniel emphasized that emotional investment should focus on outcomes, not code, which is merely a means. The best programmers write minimal, high-quality code, holding no attachment to it. Studying the domain reveals user needs, as Daniel learned during a financial project where ignorance of CDOs led to unintended consequences. Observing users’ frustrations, like manual data entry, uncovers opportunities to eliminate friction, enhancing product value.

Simplifying the Complex

Exceptional programmers see through complexity to find simple solutions. Daniel shared a story of his colleague bypassing bloated Java web servers by writing a lean one from the HTTP spec. In another case, a team debating JSON libraries was guided to implement a simple interface for nine serialized objects, avoiding heavy dependencies. Writing clear documentation, like a streamlined README, drives “embarrassment-driven refactoring,” ensuring solutions remain concise and maintainable, solving only what’s necessary.

Choosing Tools for the Problem

Tool selection should prioritize the product, not team familiarity. Daniel recounted a team learning Scala to sketch code quickly, despite no prior experience, proving adaptability trumps comfort. He advocated for polyglot programming, using Advent of Code to learn Rust and Go, which broadened his problem-solving perspective. By minimizing cognitive distance between problem and solution, as Rich Hickey’s “Simple Made Easy” suggests, programmers select tools that evolve with project needs, ensuring flexibility.

Fostering Team Care

Great programmers uplift their teams. Daniel finds joy in pairing and teaching, inspired by an XKCD comic about the “lucky 10,000” who learn something new daily. He creates environments for learning, drawing from jiu-jitsu’s teaching-first philosophy. Sending teams home to rest, as Daniel advocates, boosts effectiveness, while assuming positive intent—per Virginia Satir’s family therapy principle—builds empathy, transforming conflicts into opportunities for collaboration and growth.

Building Psychological Safety

Psychological safety, per Amy Edmondson’s research, is vital for high-performing teams. Daniel explained that safe teams encourage saying “I don’t know,” seeking help, and disagreeing without fear. A study of surgical teams showed high performers report more errors, reflecting trust, not incompetence. In software, this translates to teams where questions spark learning, help fosters collaboration, and dissent drives improvement, creating dynamic, challenging environments that fuel innovation.

Growing as a Programmer

Personal growth sustains programming excellence. Daniel urged developers to stay current through communities, contribute actively, and remain skeptical of trends like AI hype. Practicing via challenges like Advent of Code sharpens skills, as Daniel found when switching languages mid-puzzle. Balancing work with physical activities, like running, and prioritizing rest prevents burnout. By embracing continual learning and kindness, programmers evolve, as Daniel’s colleague demonstrates, into impactful, resilient professionals.

Links:

PostHeaderIcon [KotlinConf2025] Building a macOS Screen Saver with Kotlin

A captivating tale of a developer’s obsession and a journey into the less-trodden paths of Kotlin development was shared by Márton Braun, a Developer Advocate at JetBrains. It all began with a simple, yet compelling, observation at a previous KotlinConf: a screen saver featuring the bouncing Kotlin logos, reminiscent of old DVD players. Upon discovering it was merely a pre-rendered video and not a true screen saver, a challenge was born. Márton set out to build his own, a native macOS application powered by Kotlin/Native.

The project became a masterclass in interoperability and a candid exploration of the quirks of native application development. Márton detailed how Kotlin/Native’s powerful interop capabilities made it surprisingly easy to call native macOS APIs. However, this ease was often contrasted with the complexities and frustrations of working with the macOS platform itself. The development process was a constant battle, with macOS often proving to be an uncooperative partner in this creative endeavor.

Márton’s perseverance paid off, resulting in a fully functional screen saver. He even managed to create two distinct implementations: one using the traditional AppKit framework and another built with Compose Multiplatform. This dual approach not only demonstrated the capabilities of both technologies but also provided a unique learning experience. He highlighted how the Compose version allowed him to focus on the core UI logic, abstracting away the intricacies of packaging the screen saver. This is a powerful testament to Compose Multiplatform’s potential for simplifying development and improving productivity.

The screen saver project serves as an excellent case study, showcasing Kotlin’s ability to venture into unconventional domains beyond mobile and backend development. Márton successfully demonstrated that with Kotlin and the right tools, developers can create truly native applications for platforms like macOS, leveraging their existing skills and knowledge. The flexibility of Kotlin Multiplatform allows developers to share code across platforms while still delivering a native user experience.

Ultimately, this project is a celebration of the unique possibilities that Kotlin offers. It encourages developers to think creatively about how they can apply the language to solve a wide range of problems and build applications for a diverse set of platforms. Márton’s story is an inspiring reminder that sometimes the most interesting and valuable projects are born from a simple desire to see something that doesn’t exist yet come to life.

Links:


PostHeaderIcon [KotlinConf2025] Charts, Code, and Sails: Winning a Regatta with Kotlin Notebook

In the high-stakes world of competitive sailing, where every decision can mean the difference between victory and defeat, an extraordinary tool has emerged: Kotlin Notebook. Roman Belov, a distinguished member of the JetBrains team, shared a captivating account of leveraging this innovative technology to triumph in a 24-hour regatta. The narrative transcends a simple code demonstration, illustrating how interactive programming becomes a critical asset in a dynamic, unpredictable environment like the open sea.

This journey highlights the power of Kotlin Notebook as more than just a development tool; it’s a platform for real-time problem-solving. While a seasoned developer, Roman’s most cherished hat is that of a yachtsman. He uses the notebook to translate complex nautical challenges into actionable, data-driven decisions. The essence of the task is to navigate a course, which is essentially a graph with nodes representing different locations and edges representing the path between them. However, unlike a typical graph problem, the rules of sailing introduce complex variables. The boat cannot sail directly into the wind, and its speed is heavily dependent on the angle of the wind. This means the graph is constantly changing, making traditional route-planning algorithms obsolete.

The solution required a tool that could rapidly process data, visualize outcomes, and allow for on-the-fly adjustments. This is where Kotlin Notebook excelled, providing a live, interactive environment. Roman outlined how he could use the notebook to perform crucial tasks in the middle of the race: visualizing the race course on a map, calculating the fastest path based on current wind conditions, and dynamically adjusting the route as the wind shifted. This is achieved by creating a “sailable roads” model, which evaluates every potential path on the graph at regular intervals and discards any that are impossible given the wind direction. For the remaining paths, the notebook computes the optimal boat speed and time to complete that segment, effectively modeling the race in real time.

Roman then showcased the brute-force search algorithm that was used to find the optimal path. The code, written in Kotlin, was surprisingly straightforward and demonstrated the language’s elegance and readability. The algorithm, running within the notebook, would constantly iterate through the potential paths, calculating the time to finish for each one and discarding any that were slower than the best time found so far. The visual output of the notebook, which could render the different routes directly on the map, was a game-changer. It transformed abstract data and calculations into a clear, visual representation that allowed the sailors to make quick, informed decisions.

The application of Kotlin Notebook in this unconventional scenario proves its versatility beyond traditional data science or development tasks. It demonstrated how a tool designed for rapid experimentation can be applied to complex, real-world problems. The interactive nature of the notebook allowed Roman to combine data analysis, algorithm execution, and visual feedback into a single, cohesive workflow, enabling him and his crew to stay ahead of the competition and ultimately, win the race. This story is a testament to the power of a modern programming language and an adaptable toolchain, turning a challenging maritime endeavor into an exciting display of computational prowess.

Links:


PostHeaderIcon [NDCOslo2024] Mirror, Mirror: LLMs and the Illusion of Humanity – Jodie Burchell

In the mesmerizing mirror maze of machine mimicry, where words weave worlds indistinguishable from wit, Jodie Burchell, JetBrains’ data science developer advocate, shatters the spell of sentience in large language models (LLMs). A PhD psychologist turned NLP pioneer, Jodie probes the psychological ploys that propel projections of personhood onto probabilistic parsers, dissecting claims from consciousness to cognition. Her inquiry, anchored in academia and augmented by anecdotes, advises acuity: LLMs as linguistic lenses, not living likenesses, harnessing their heft while heeding hallucinations.

Jodie greets with gratitude for her gritty slot, her hipster cred in pre-prompt NLP notwithstanding. LLMs’ 2022 blaze beguiles: why bestow brains on bytes when other oracles oblige? Her hypothesis: humanity’s hall of mirrors, where models mirror our mores, eliciting empathy from echoes.

Psychological Projections: Perceiving Personhood in Parsers

Humans, Jodie hazards, hallucinate humanity: anthropomorphism’s ancient artifice, from pets to puppets. LLMs lure with language’s liquidity—coherent confessions conjure companionship. She cites stochastic parrots: parleying patterns, not pondering profundities, yet plausibility persuades.

Extraordinary assertions abound: Blake Lemoine’s LaMDA “alive,” Google’s Gemini “godhead.” Jodie juxtaposes: sentience’s scaffold—selfhood, suffering—sans in silicon. Chalmers’ conundrum: consciousness connotes qualia, quanta qualms quell in qubits.

Levels of Luminescence: From Language to Luminary

DeepMind’s AGI arc: Level 1 chatbots converse convincingly; Level 2 reasons reactively; Level 3 innovates imaginatively. LLMs linger at 1-2, lacking Level 4’s abstraction or 5’s autonomy. Jodie jests: jackdaws in jester’s garb, juggling jargon sans judgment.

Illusions intensify: theory of mind’s mirage, where models “infer” intents from inferences. Yet, benchmarks belie: ARC’s abstraction stumps, BIG-bench’s breadth baffles—brilliance brittle beyond basics.

Perils of Projection: Phishing and Philosophical Pitfalls

Prompt injections prey: upstream overrides oust origins, birthing bogus bounties—”Amazon voucher via arcane URL.” Jodie demonstrates: innocuous inquiries infected, innocuousness inverted into inducements. Robustness rankles: rebuttals rebuffed, ruses reiterated.

Her remedy: recognize reflections—lossy compressions of lore, not luminous lives. Demystify to deploy: distill data, detect delusions, design defensively.

Dispelling the Delusion: Harnessing Heuristics Humanely

Jodie’s jeremiad: myths mislead, magnifying misuses—overreach in oracles, oversight in safeguards. Her horizon: LLMs as lucid lenses, amplifying analysis while acknowledging artifice.

Links:

PostHeaderIcon [KotlinConf2024] Channels in Kotlin Coroutines: Unveiling the Redesign

At KotlinConf2024, Nikita Koval, a JetBrains concurrency expert, delved into Kotlin coroutine channels, a core communication primitive. Channels, often used indirectly via APIs like Flow, enable data transfer between coroutines. Nikita explored their redesigned implementation, which boosts performance and reduces memory usage. He detailed rendezvous and buffered channel semantics, underlying algorithms, and scalability, offering developers insights into optimizing concurrent applications and understanding coroutine internals.

Channels: The Hidden Backbone of Coroutines

Channels are fundamental to Kotlin coroutines, even if developers rarely use them directly. Nikita highlighted their role in high-level APIs like Flow. For instance, merging two Flows or collecting data across dispatchers relies on channels to transfer elements between coroutines. Channels also bridge reactive frameworks like RxJava, funneling data through a coroutine-launched channel. Unlike sequential Flows, channels enable concurrent data handling, making them essential for complex asynchronous tasks, as seen in Flow’s channelFlow builder.

Rendezvous Channels: Synchronized Data Exchange

Rendezvous channels, the default in Kotlin, ensure synchronized communication. Nikita illustrated their semantics with two producers and one consumer. When a consumer calls receive on an empty channel, it suspends until a producer sends data. Conversely, a producer’s send suspends if no consumer is waiting, preventing uncontrolled growth. This “rendezvous” ensures direct data handoff, as demonstrated when a producer resumes a waiting consumer, maintaining efficiency and safety in concurrent scenarios.

Building Efficient Channel Algorithms

Implementing rendezvous channels requires balancing efficiency, memory use, and scalability. Nikita compared concurrent queue designs to adapt for channels. A lock-based sequential queue, while fast on single threads, fails to scale due to synchronization costs. Java’s ConcurrentLinkedQueue, using a linked list, scales better but incurs high memory overhead—32 bytes per 4-byte reference. Instead, modern queue designs use a segmented array with atomic counters for enqueuing and dequeuing, minimizing memory and scaling effectively, forming the basis for channel implementation.

Buffered Channels: Flexible Data Buffering

Buffered channels extend rendezvous semantics by allowing a fixed-capacity buffer. Nikita explained that a channel with capacity k accepts k elements without suspension, suspending only when full. Using a single producer-consumer example, he showed how a producer fills an empty buffer, while a second producer suspends until the consumer extracts an element, freeing space. This design, implemented with an additional counter to track buffer boundaries, supports dynamic workloads, though cancellation semantics add complexity, detailed in JetBrains’ research papers.

Performance Gains from Redesign

The channel redesign significantly enhances performance. Nikita shared benchmarks comparing the old linked-list-based implementation to the new segmented array approach. In a multi-producer, multi-consumer test with 10,000 coroutines, the new channels scaled up to four times faster, producing less garbage. Even in sequential workloads, they were 20% quicker. Q&A revealed further tuning, like setting segment sizes to 32 elements, balancing memory and metadata overhead, ensuring scalability across 64-core systems without degradation.

Deepening Concurrency Knowledge

Understanding channel internals empowers developers to tackle performance issues, akin to knowing hash table mechanics. Nikita emphasized that while high-level APIs abstract complexity, low-level knowledge aids debugging. He invited attendees to explore further at the PDI conference in Copenhagen, where JetBrains will discuss coroutine algorithms, including schedulers and mutexes. The redesigned channels, applied to unlimited and conflated variants, offer robust, scalable communication, encouraging developers to leverage coroutines confidently in high-load applications.

Links:

PostHeaderIcon [KotlinConf2024] Compose UI on a Light Switch: KotlinConf2024’s Embedded Adventure

At KotlinConf2024, Jake Wharton, a Kotlin enthusiast, shared his journey of running Compose UI on a smart light switch powered by embedded Linux. Sparked by a friend’s discovery of a backdoor granting root access, Jake transformed a $50 Amazon switch into a custom platform. He navigated challenges from setting up a JVM and Kotlin Native to configuring a graphics stack with Skia and handling touch inputs, culminating in a live demo of a touchable UI controlling the switch’s relay, showcasing Compose UI’s multiplatform potential.

A Side Project Ignited by a Backdoor

Jake’s project began in January 2023 when a friend revealed a smart switch’s ADB server allowed password-free root access, discovered via Home Assistant forums. The Decora-style switch, with a touchscreen, light sensor, and microphone, ran a stripped-down Linux. Jake snipped an extension cord to power it and confirmed root access via ADB, setting the stage for custom software. This accessibility, though later patched by the manufacturer, fueled his ambition to replace the Flutter-based UI with Compose UI, blending curiosity with technical challenge.

Bootstrapping the JVM and Kotlin Native

To run Compose UI, Jake first tested the JVM on the switch’s limited 150MB storage. He pushed a Linux ARM JRE and a Java “Hello World” class, confirming JVM functionality. Next, he compiled a Kotlin Native “Hello World” for Linux ARM, proving Kotlin could run natively. These steps established a foundation, but the switch’s constraints—no compiler, minimal storage—required compiling on a host machine and transferring binaries, a process complicated by the need to match the device’s library versions, like libDRM 2.4.

Wrestling with the Graphics Stack

Rendering Compose UI required a graphics stack, but the switch’s Flutter app used Linux’s Direct Rendering Manager (DRM) with OpenGL ES, not OpenGL. Jake’s initial attempt to use Compose UI Desktop failed due to missing OpenGL and X11 dependencies. He ported C-based DRM code to Kotlin Native, meticulously matching the switch’s libDRM version (2.4.87) by analyzing binaries. This process, spanning months, involved pulling headers and shared objects from the device, ensuring compatibility, and overcoming compilation hurdles, like missing toolchains for Linux ARM.

Skia: Rendering Pixels with Kotlin

To draw pixels, Jake turned to Skia, the graphics library powering Flutter and Android. JetBrains’ Skiko library, binding Skia to Kotlin, lacked Linux ARM support for OpenGL ES. Jake forked Skiko, modifying it to use EGL, and endured weeks of GitHub Actions builds to compile Skia for ARM. He integrated Skiko’s C++ and Kotlin bindings, enabling rendering of basic shapes (e.g., red backgrounds, blue circles). This step, though painful, proved Kotlin Native could handle the switch’s display, setting the stage for Compose UI.

Handling Touch Inputs

Interactivity required processing touchscreen inputs. Jake used Linux’s evtest to identify the switch’s touchscreen events, capturing X/Y positions and touch states (down/up). He implemented a single-pointer event parser in Kotlin Native, mapping raw events to a data class within the render loop. This avoided multi-touch complexity, as the switch supported only one pointer. By feeding these events to Compose UI, Jake enabled touch interactions, like button ripples, transforming the switch into a responsive interface, despite occasional crashes during live demos.

Bringing Compose UI to Life

Integrating Compose UI was surprisingly straightforward compared to prior challenges. Jake forked JetBrains’ Compose UI repository, adding a Linux ARM target and implementing expect/actual declarations for dependencies like input handling and scrolling. He replaced low-level Skiko calls with Compose UI’s entry point, passing a Skia canvas and touch events. Initial text rendering crashed due to font issues, but a simple button worked, displaying ripples on touch. Jake’s UI, controlling the switch’s relay via a Unix domain socket and Ktor, demonstrated Compose UI’s adaptability, running the same code on desktop for development.

Demo and Future Potential

Jake’s live demo, despite power converter issues, showcased a draggable switch UI toggling a light bulb, built with Compose UI and Kotlin multiplatform. An enclosure housed the switch, highlighting its real-world application. He envisioned future enhancements, like Home Assistant integration or music control, noting the project’s infancy. Community contributions, like his friend Eric’s interactive component, and public forks for Skiko and Ktor, underscore the project’s collaborative spirit. Jake cautioned against internet-connecting the switch due to security concerns, urging manufacturers to simplify hacking for innovation.

Links: