Recent Posts
Archives

Posts Tagged ‘Kotlin’

PostHeaderIcon [DevoxxUK2025] Kotlin: The New and Noteworthy

Anton Arhipov, a developer advocate from JetBrains, captivated the DevoxxUK2025 audience with an overview of Kotlin’s recent advancements and future roadmap. Focusing on Kotlin 2.0’s K2 compiler and upcoming features like guard conditions, context parameters, rich errors, and name-based destructuring, Anton highlighted how Kotlin balances conciseness, safety, and expressiveness. His interactive talk, enriched with personal anecdotes and live demos, underscored Kotlin’s evolution as a versatile, multi-platform language that empowers developers to write robust, readable code.

Kotlin 2.0 and the K2 Compiler

Anton introduced Kotlin 2.0, released nearly a year ago, emphasizing the K2 compiler’s new front-end intermediate representation (FIR) and control flow engine. K2 improved compilation performance by 40% in IntelliJ IDEA Ultimate, fixed numerous small bugs, and provided a scalable foundation for future features. By desugaring complex constructs (e.g., if to when expressions, for loops to iterators), K2 enhances smart casts and type inference, enabling seamless handling of nullable types and complex expressions without manual casting.

Guard Conditions for Safer Control Flow

Set to stabilize in Kotlin 2.2, guard conditions enhance when expressions by allowing conditional checks without variable binding. In a demo, Anton showed processing orders with guard conditions to handle subscriptions and discounts, reducing repetition and ensuring exhaustiveness. Unlike Java’s pattern matching, Kotlin leverages existing destructuring to avoid redundancy, with guard conditions adding logical safety by enforcing checks (e.g., amount > 100) directly in when branches, minimizing errors in complex control flows.

Name-Based Destructuring for Robustness

Anton discussed name-based destructuring, planned for experimental release in Kotlin 2.4. Unlike positional destructuring, which risks logical errors during refactoring, name-based destructuring matches variable names to class properties, improving readability and safety. This feature extends to non-data classes and sealed hierarchies, with plans to deprecate positional destructuring in future versions (e.g., Kotlin 3.0), ensuring long-term language consistency while maintaining backward compatibility.

Context Parameters for Scoped APIs

Context parameters, entering beta in Kotlin 2.2, enable scoped extension functions for type-safe builders, often mistaken for DSLs. Anton demonstrated a client-building DSL where an infix extension function for dates (e.g., 10 March 2000) was restricted to a specific context, preventing global namespace pollution. This feature supports library developers in creating intuitive APIs, such as dependency injection-like logger scoping, reducing boilerplate and enhancing code clarity without compromising safety.

Rich Errors for Expressive Error Handling

Planned for experimental release in Kotlin 2.4, rich errors (previously called union types for errors) introduce a new error class syntax to distinguish error types explicitly. In a demo, Anton showed how rich errors improve over null-based error handling in functions like fetchUser and parseUser, enabling clear differentiation between network and parsing errors. Using when expressions, developers gain exhaustiveness checks and readable error handling, avoiding the verbosity of sealed hierarchies or result types.

Enhancing Compiler Safety with Return Value Checks

Anton highlighted a Kotlin 2.2 feature that mandates checking return values for standard library functions, preventing logical errors like missing return statements or incorrect function calls (e.g., using sort instead of sorted). By marking core functions with annotations, the compiler issues warnings for unused return values, reducing bugs like those in a demo where sorting a mutable list failed due to an overlooked return. This opt-in feature will expand to application code, enhancing reliability.

Links:

PostHeaderIcon [KotlinConf2025] Build your Kotlin and Android apps with Buck2

Sergei Rybalkin, a software engineer from Meta, introduced the audience to Buck2, an open-source build system that is now equipped to support Kotlin and Android applications. In a concise and informative presentation, Rybalkin detailed how Buck2, a successor to the original Buck system, addresses the need for a fast and scalable build solution, particularly for large-scale projects like those at Meta. The talk centered on Buck2’s core principles and its capabilities for accelerating development cycles and ensuring consistent, reliable builds.

The Power of a Scalable Build System

Rybalkin began by outlining the motivation behind Buck2. He explained that as projects grow in size and complexity, traditional build systems often struggle to keep up, leading to slow incremental iterations and hindered developer productivity. Buck2 was designed to overcome these challenges by focusing on key areas such as parallelism and a highly opinionated approach to optimization. The talk revealed that Buck2’s architecture allows it to execute build tasks with remarkable efficiency, a crucial factor for Meta’s own internal development processes. Rybalkin also touched on advanced capabilities like Remote Execution and the Build Tools API, which further enhance the system’s performance and flexibility.

A Blueprint for Optimization

The presentation also shed light on Buck2’s philosophy of “opinionated optimization.” Rybalkin clarified that this means the system takes a firm stance on how things should be done to achieve the best results. For example, if a particular feature or integration does not perform well, the Buck2 team may choose to drop support for it entirely, rather than provide a subpar experience. This selective approach ensures that the build system remains fast and reliable, even as it handles a multitude of dependencies and complex configurations. Rybalkin underscored the fact that the open-source version of Buck2 is almost identical to the internal solution used at Meta, offering the community the same powerful tools and optimizations that drive one of the world’s largest development teams. He concluded by encouraging the audience to try Buck2 and provide feedback, underscoring the collaborative nature of open-source development.

Links:

PostHeaderIcon [KotlinConf2024] Compose Multiplatform Evolves on iOS and Beyond

At KotlinConf2024, Sebastian Aigner, a JetBrains developer advocate, unveiled advancements in Compose Multiplatform, now in beta for iOS and alpha for web. Extending beyond business logic, Compose enables shared UI across platforms, integrating native capabilities. Sebastian showcased new common APIs—previews, resources, lifecycle, navigation, and UI testing—alongside iOS-specific enhancements like accessibility and scroll physics. Through live demos, he demonstrated how these features simplify cross-platform development, inviting developers to shape Compose’s future with feedback.

A Year of Progress for Compose Multiplatform

Since its debut at KotlinConf2023, Compose Multiplatform has matured significantly. Sebastian highlighted its role in sharing UI code, complementing Kotlin Multiplatform’s business logic sharing. On Android, it leverages Jetpack Compose; on desktop, it powers JetBrains Toolbox; and on iOS, it reached beta status at KotlinConf2024. The web target hit alpha, broadening its reach. Progress spans accessibility, navigation, text input, and scroll physics, with most features now stable or experimental, ready for developers to adopt and refine through real-world use.

iOS-Specific Enhancements

Compose Multiplatform on iOS now feels native, thanks to revamped scroll physics mirroring iOS’s overscroll and spring effects. Sebastian demonstrated accessibility improvements, with components supporting VoiceOver and gesture navigation out of the box, provided content descriptions are added. Interop with SwiftUI allows popups to span the screen, and window insets APIs handle notches and dynamic islands, ensuring full-screen rendering. These enhancements make iOS apps built with Compose visually and functionally indistinguishable from native counterparts, enhancing user experience.

Common Resources for Seamless UI

The new common resources API simplifies asset management. Sebastian showed how to add drawables and strings in a composeResources directory, accessed via a type-safe res object. In a demo, he added a banner image and a localized conference description, with Fleet auto-generating accessors. Support for multimodule resources and translations (e.g., German dark mode) ensures flexibility. This API, familiar from Android, reduces boilerplate, letting developers focus on crafting polished, platform-agnostic UIs with minimal effort.

Lifecycle and View Models in Common Code

Compose Multiplatform now supports common lifecycle and view model APIs, enabling robust app architecture. Sebastian demonstrated a lifecycle logger tracking states like onCreate and onPause, with collectAsStateWithLifecycle ensuring efficient flow collection. In a view model demo, he outsourced mood-tracking logic, using a factory function to instantiate it. Integration with Koin for dependency injection and lifecycle-aware state collection streamlines development, making MVVM patterns viable across platforms without platform-specific workarounds.

Navigation for Cross-Platform Apps

Navigation, a cornerstone of multiplatform apps, is now available via a Jetpack Navigation-inspired API. Sebastian built a demo app with a fruit list and detail pages, using a NavHost and NavController for stack-based navigation. Features like window insets padding, animated transitions, and rememberSaveable for state persistence ensure a native feel. Type-safe routing with Kotlinx.serialization is in development, reducing errors. This API, while optional, simplifies porting Android navigation logic to iOS and beyond, enhancing developer productivity.

UI Testing and Community Feedback

A new common UI testing API allows writing tests once for all platforms. Sebastian showed a test verifying a composable’s text content, executed across targets. This reduces testing overhead, ensuring consistent behavior. He urged developers to try these features, citing the Compose Multiplatform portal (jb.compose) for documentation. Feedback via the Kotlin Slack and issue tracker is vital, as community input drives stabilization. With support for features like strong skipping mode and shared element transitions, Compose continues to evolve dynamically.

Links:

PostHeaderIcon [KotlinConf2024] Compose Multiplatform Evolves on iOS and Beyond

At KotlinConf2024, Sebastian Aigner, a JetBrains developer advocate, unveiled advancements in Compose Multiplatform, now in beta for iOS and alpha for web. Extending beyond business logic, Compose enables shared UI across platforms, integrating native capabilities. Sebastian showcased new common APIs—previews, resources, lifecycle, navigation, and UI testing—alongside iOS-specific enhancements like accessibility and scroll physics. Through live demos, he demonstrated how these features simplify cross-platform development, inviting developers to shape Compose’s future with feedback.

A Year of Progress for Compose Multiplatform

Since its debut at KotlinConf2023, Compose Multiplatform has matured significantly. Sebastian highlighted its role in sharing UI code, complementing Kotlin Multiplatform’s business logic sharing. On Android, it leverages Jetpack Compose; on desktop, it powers JetBrains Toolbox; and on iOS, it reached beta status at KotlinConf2024. The web target hit alpha, broadening its reach. Progress spans accessibility, navigation, text input, and scroll physics, with most features now stable or experimental, ready for developers to adopt and refine through real-world use.

iOS-Specific Enhancements

Compose Multiplatform on iOS now feels native, thanks to revamped scroll physics mirroring iOS’s overscroll and spring effects. Sebastian demonstrated accessibility improvements, with components supporting VoiceOver and gesture navigation out of the box, provided content descriptions are added. Interop with SwiftUI allows popups to span the screen, and window insets APIs handle notches and dynamic islands, ensuring full-screen rendering. These enhancements make iOS apps built with Compose visually and functionally indistinguishable from native counterparts, enhancing user experience.

Common Resources for Seamless UI

The new common resources API simplifies asset management. Sebastian showed how to add drawables and strings in a composeResources directory, accessed via a type-safe res object. In a demo, he added a banner image and a localized conference description, with Fleet auto-generating accessors. Support for multimodule resources and translations (e.g., German dark mode) ensures flexibility. This API, familiar from Android, reduces boilerplate, letting developers focus on crafting polished, platform-agnostic UIs with minimal effort.

Lifecycle and View Models in Common Code

Compose Multiplatform now supports common lifecycle and view model APIs, enabling robust app architecture. Sebastian demonstrated a lifecycle logger tracking states like onCreate and onPause, with collectAsStateWithLifecycle ensuring efficient flow collection. In a view model demo, he outsourced mood-tracking logic, using a factory function to instantiate it. Integration with Koin for dependency injection and lifecycle-aware state collection streamlines development, making MVVM patterns viable across platforms without platform-specific workarounds.

Navigation for Cross-Platform Apps

Navigation, a cornerstone of multiplatform apps, is now available via a Jetpack Navigation-inspired API. Sebastian built a demo app with a fruit list and detail pages, using a NavHost and NavController for stack-based navigation. Features like window insets padding, animated transitions, and rememberSaveable for state persistence ensure a native feel. Type-safe routing with Kotlinx.serialization is in development, reducing errors. This API, while optional, simplifies porting Android navigation logic to iOS and beyond, enhancing developer productivity.

UI Testing and Community Feedback

A new common UI testing API allows writing tests once for all platforms. Sebastian showed a test verifying a composable’s text content, executed across targets. This reduces testing overhead, ensuring consistent behavior. He urged developers to try these features, citing the Compose Multiplatform portal (jb.compose) for documentation. Feedback via the Kotlin Slack and issue tracker is vital, as community input drives stabilization. With support for features like strong skipping mode and shared element transitions, Compose continues to evolve dynamically.

Links:

PostHeaderIcon [KotlinConf2025] LangChain4j with Quarkus

In a collaboration between Red Hat and Twilio, Max Rydahl Andersen and Konstantin Pavlov presented an illuminating session on the powerful combination of LangChain4j and Quarkus for building AI-driven applications with Kotlin. The talk addressed the burgeoning demand for integrating artificial intelligence into modern software and the common difficulties developers encounter, such as complex setups and performance bottlenecks. By merging Kotlin’s expressive power, Quarkus’s rapid runtime, and LangChain4j’s AI capabilities, the presenters demonstrated a streamlined and effective solution for creating cutting-edge applications.

A Synergistic Approach to AI Integration

The core of the session focused on the seamless synergy between the three technologies. Andersen and Pavlov detailed how Kotlin’s idiomatic features simplify the development of AI workflows. They presented a compelling case for using LangChain4j, a versatile framework for building language model-based applications, within the Quarkus ecosystem. Quarkus, with its fast startup times and low memory footprint, proved to be an ideal runtime for these resource-intensive applications. The presenters walked through practical code samples, illustrating how to set up the environment, manage dependencies, and orchestrate AI tools efficiently. They emphasized that this integrated approach significantly reduces the friction typically associated with AI development, allowing engineers to focus on business logic rather than infrastructural challenges.

Enhancing Performance and Productivity

The talk also addressed the critical aspect of performance. The presenters demonstrated how the combination of LangChain4j and Quarkus enables the creation of high-performing, AI-powered applications. They discussed the importance of leveraging Quarkus’s native compilation capabilities, which can lead to dramatic improvements in startup time and resource utilization. Additionally, they touched on the ongoing work to optimize the Kotlin compiler’s interaction with the Quarkus build system. Andersen noted that while the current process is efficient, there are continuous efforts to further reduce build times and enhance developer productivity. This commitment to performance underscores the value of this tech stack for developers who need to build scalable and responsive AI solutions.

The Path Forward

Looking ahead, Andersen and Pavlov outlined the future roadmap for LangChain4j and its integration with Quarkus. They highlighted upcoming features, such as the native asynchronous API, which will provide enhanced support for Kotlin coroutines. While acknowledging the importance of coroutines for certain use cases, they also reminded the audience that traditional blocking and virtual threads remain perfectly viable and often preferred for a majority of applications. They also extended an open invitation to the community to contribute to the project, emphasizing that the development of these tools is a collaborative effort. The session concluded with a powerful message: this technology stack is not just about building applications; it’s about empowering developers to confidently tackle the next generation of AI-driven projects.

Links:

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 [KotlinConf2025] The Life and Death of a Kotlin Native Object

The journey of an object within a computer’s memory is a topic that is often obscured from the everyday developer. In a highly insightful session, Troels Lund, a leader on the Kotlin/Native team at Google, delves into the intricacies of what transpires behind the scenes when an object is instantiated and subsequently discarded within the Kotlin/Native runtime. This detailed examination provides a compelling look at a subject that is usually managed automatically, demonstrating the sophisticated mechanisms at play to ensure efficient memory management and robust application performance.

The Inner Workings of the Runtime

Lund begins by exploring the foundational elements of the Kotlin/Native runtime, highlighting its role in bridging the gap between high-level Kotlin code and the native environment. The runtime is responsible for a variety of critical tasks, including memory layout, garbage collection, and managing object lifecycles. One of the central tenets of this system is its ability to handle memory allocation and deallocation with minimal developer intervention. The talk illustrates how an object’s structure is precisely defined in memory, a crucial step for both performance and predictability. This low-level perspective offered a new appreciation for the seamless operation that developers have come to expect.

A Deep Dive into Garbage Collection

The talk then progresses to the sophisticated mechanisms of garbage collection. A deep dive into the Kotlin/Native memory model reveals a system designed for both performance and concurrency. Lund describes the dual approach of a parallel mark and concurrent sweep and a concurrent mark and sweep. The parallel mark and concurrent sweep is designed to maximize throughput by parallelizing the marking phase, while the concurrent mark and sweep aims to minimize pause times by allowing the sweeping phase to happen alongside application execution. The session details how these processes identify and reclaim memory from objects that are no longer in use, preventing memory leaks and maintaining system stability. The discussion also touches upon weak references and their role in memory management. Lund explains how these references are cleared out in a timely manner, ensuring that objects that should be garbage-collected are not resurrected.

Final Thoughts on the Runtime

In his concluding remarks, Lund offers a final summary of the Kotlin/Native runtime. He reiterates that this is a snapshot of what is happening now, and that the details are subject to change over time as new features are added and existing ones are optimized. He emphasizes that the goal of the team is to ensure that the developer experience is as smooth and effortless as possible, with the intricate details of memory management handled transparently by the runtime. The session serves as a powerful reminder of the complex engineering that underpins the simplicity and elegance of the Kotlin language, particularly in its native context.

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 [KotlinConf2025] Code Quality at Scale: Future Proof Your Android Codebase with KtLint and Detekt

Managing a large, multi-team codebase is a monumental task, especially when it has evolved over many years. Introducing architectural changes and maintaining consistency across autonomous teams adds another layer of complexity. In a comprehensive discussion, Tristan Hamilton, a distinguished member of the HubSpot team, presented a strategic approach to future-proofing Android codebases by leveraging static analysis tools like KtLint and Detekt.

Tristan began by framing the challenges inherent in a codebase that has grown and changed for over eight years. He emphasized that without robust systems, technical debt can accumulate, and architectural principles can erode as different teams introduce their own patterns. The solution, he proposed, lies in integrating automated guardrails directly into the continuous integration (CI) pipeline. This proactive approach ensures a consistent level of code quality and helps prevent the introduction of new technical debt.

He then delved into the specifics of two powerful static analysis tools: KtLint and Detekt. KtLint, as a code linter, focuses on enforcing consistent formatting and style, ensuring that the codebase adheres to a single, readable standard. Detekt, on the other hand, is a more powerful static analysis tool that goes beyond simple style checks. Tristan highlighted its ability to perform advanced analysis, including type resolution, which allows it to enforce architectural patterns and detect complex code smells that a simple linter might miss. He shared practical examples of how Detekt can be used to identify and refactor anti-patterns, such as excessive class size or complex methods, thereby improving the overall health of the codebase.

A significant part of the talk was dedicated to a specific, and crucial, application of these tools: safely enabling R8, the code shrinker and optimizer, in a multi-module Android application. The process is notoriously difficult and can often lead to runtime crashes if not handled correctly. Tristan showcased how custom Detekt rules could be created to enforce specific architectural principles at build time. For instance, a custom rule could ensure that certain classes are not obfuscated or that specific dependencies are correctly handled, effectively creating automated safety nets. This approach allowed the HubSpot team to gain confidence in their R8 configuration and ship with greater speed and reliability.

Tristan concluded by offering a set of key takeaways for developers and teams. He underscored the importance of moving beyond traditional static analysis and embracing tools that can codify architectural patterns. By automating the enforcement of these patterns, teams can ensure the integrity of their codebase, even as it grows and evolves. This strategy not only reduces technical debt but also prepares the codebase for future changes, including the integration of new technologies and methodologies, such as Large Language Model (LLM) generated code. It is a powerful method for building robust, maintainable, and future-ready software.

Links: