Visual Studio Kotlin



Mobile

Nabil Hachicha, Android Engineer, from MongoDB Realm shares their story of creating a pure Kotlin-first SDK for use by developers.

Realm is an open-source, easy-to-use local database that helps mobile developers to build better apps faster. It launched 8 years ago with the release of the Realm Java SDK, and since then we’ve worked to make sure our API is always improving to reflect what mobile developers need.

Kotlin is a hot programming language right now, and its eclipse of Java for Android mobile development might leave Visual Studio developers wondering how they can get in on the action. Kotlin has great support and many contributors in its fast-growing global community. Enjoy the benefits of a rich ecosystem with a wide range of community libraries. Help is never far away – consult extensive community resources or ask the Kotlin team directly. Join the community →. Kotlin IDE for Visual Studio Code Smart code completion, linting, debugging, formatting and more for Kotlin in VSCode using the Kotlin language server and the Kotlin debug adapter. To use, open a Kotlin file inside a Gradle or Maven project. Support for Kotlin source files with a. Search results for 'kotlin', Visual Studio Code on marketplace.visualstudio.com. Programming with Kotlin in Visual Studio Code Kotlin is all the rage now that it has been deemed a first-class programming language for developing Android apps. Actually, it's been raging all on its own for a while now, as evidenced by the Stack Overflow Trends chart below.

As Kotlin has grown to become the recommended language for building Android apps, we’ve made iterative improvements to our Realm Java SDK to make sure the API is compatible. But even with various releases over the past few years — via providing helper extension functions to improve using the Realm API with Kotlin — we knew Realm would ultimately benefit from the design and implementation of a pure Kotlin-first SDK for use by developers.

In the post, we take you through what motivated the Realm Engineering team’s decision to build a new SDK from the ground-up, and we share some of the key design principles that guided the development of Realm’s Kotlin Multiplatform SDK.

Background

As usage of Kotlin grew among Android developers, Realm’s engineering team started to use Kotlin in our testing environment. This led to introducing helper functions like Query with generic type; executeTransactionAwait – which runs transactions inside coroutines — and JSR305 annotation to improve the strict null-safety type system with Kotlin.

But even with this work, there were still architectural shifts that were difficult to solve, like users adopting unidirectional dataflows based on immutability. The wider Realm community also asked us to provide a more idiomatic Kotlin API that would enable a type safe query builder, among other API improvements. We knew some of these enhancements would require a fundamental refactoring and we wanted to meet our users’ needs. So Realm’s Engineering team started to design and implement a pure Kotlin first SDK for the mobile ecosystem.

Why a Multiplatform Library?

At the same time we began to lay the foundation of our Kotlin SDK, Kotlin Multiplatform started to mature, and we quickly realized we should build Realm’s new Kotlin SDK as a Multiplatform library. There were surprisingly few multiplatform libraries for the persistence layer, and as a multiplatform mobile database, we knew Realm could help fill this gap for developers. We had an opportunity to allow Kotlin developers to build cross platform applications in the same way that Realm’s developers use our React Native and Xamarin SDKs today.

Challenges

Porting the existing Realm-Java code to work on Multiplatform was an interesting (and challenging) task for Realm’s engineers because we currently use some technologies that are platform dependent.

To define a Realm schema, we use the annotation processor to generate a proxy class and then use the Gradle Transform API to do bytecode weaving with Javassist. Both tools are Kotlin JVM specific and are not compatible with Kotlin/Native.

Similarly, Reflection is only partially supported on Kotlin/Native, so any API design based on dynamic runtime instantiation would simply not work — like the Class.forName or class.newInstance primitives.

And, concurrency and the memory model are fundamentally different between platforms. The Kotlin/JVM has a Garbage Collector, whereas Kotlin/Native relies on reference counting with a cyclic collector.

To successfully build a multiplatform Kotlin Native SDK for Realm, we’d need to figure out how to re-architect the SDK in a way that would address these challenges.

The Solution

Note from the Kotlin team: Compiler plugins, compiler internal API, and Cleaner API are not stable yet and will likely change in the future.

Compiler Plugin to the Rescue

Realm’s engineering team quickly decided we would need to build our own fully-fledged compiler plug-in because existing options posed too many constraints.

The Kotlin Symbol Processing API is limited to generating new Kotlin code instead of modifying existing classes, meaning it wouldn’t suit our needs. Realm had used the Kotlin Annotation processor (KAPT) in our Kotlin support for the Realm Java SDK, but it didn’t have a native annotation processing system. Instead, the Realm Java SDK generates Java stubs containing all the declarations and annotations without the methods body. It then runs the Java annotation processor on those stubs, which feeds back to KAPT and Kotlin compiler for another round. This makes compilation and refactoring slow, and isn’t available for Kotlin/Native.

At a high level, the Realm compiler plugin‘s main goal is to make defining Realm models as simple as constructing a regular Kotlin class. This is achieved by modifying the Intermediate Representation (IR) of the compiled Kotlin code in order to change the behaviour of the property accessor (getters and setters). Once this is done a developer can now call Realm’s runtime APIs so that read/writing changes the value of the property instead of the backing field. This is done using a Lowering pass on the IR.

The other task of the compiler plugin is to collect all Realm model classes in order to automatically create a schema definition of a Realm. Since the Compiler plugin API was not yet stable and documented (1.4.30 makes JVM IR Beta stable), we reverse engineered the IR code we needed to write in order to obtain the desired generated code.

Here’s what that looks like:

First, we write the Kotlin code we want the compiler to generate in a classic Kotlin/JVM project. Then we add the compiler flag to use IR and to dump the content of the IR.

Kotlin visual studio 2017

This will dump a text file containing the IR code generated by the compiler before transforming it into JVM ByteCode. We then use this IR dump to work out what IR API calls we need to use to produce the desired output. We also use kotlin-compile-testing library to unit test the IR output from the Realm compiler plugin that matches the expected IR.

Assembly language in visual studio

Releasing Native Resources

Under the hood the Realm SDKs use a C++ storage engine. The compiler plugin adds infrastructure to link the Kotlin objects with the underlying C objects by adding a synthetic native pointer property. This holds the value of the C/ C++ pointer, allowing access to the underlying persisted value inside the storage engine.

In order to avoid leaking memory, the native pointer needs to be closed when the original Kotlin object goes out of scope.
Since Kotlin/JVM and Kotlin/Native have different memory models, we decided to use two approaches. For Kotlin/JVM we rely on the same technique we use in the current Realm-Java SDK, which is based on the usage of the reference API to track pointers that need to be cleaned once their original Java counterpart is eligible for GC.


For more information about reference API and phantom reference check out this excellent talk by Bob Lee

Note from the Kotlin team: Cleaner API is not stable yet and will change in the future.

Kotlin/Native doesn’t have a Garbage collector. It uses reference counting with a cycle collector instead. Recently the Kotlin/Native team introduced the Cleaner API. This API can be used similarly to a Finalizer/Destructor block that runs after the encompassing object has been disposed of. We use this API to perform cleanups and free native pointers.

Visual Studio Kotlin

Encapsulating the native pointers in an object with the above deallocation strategies, which hook into the normal memory management, frees us from handling explicit deallocations where we use native pointers.

Native code abstraction

Accessing the custom C++ storage engine used by the Realm SDKs varies between Kotlin/JVM and Kotlin/Native. To simplify this, we added a C layer on top, which makes it easy to use tools like cinterop to interface and generate Kotlin stubs. The C layer also allowed us to avoid writing manual JNI code to access the C++ layer, thanks to SWIG tool that generates the corresponding Java and JNI stubs.

We also leveraged the expect/actual mechanism from Kotlin Multiplatform to build a module that hides the specifics of accessing Cinterop and SWIG layers in a platform agnostic manner. This allowed us to focus the design of the library API in a platform-independent way, and to do it in another module that will become the user facing public API.

This process encourages to think about features — like querying and writing to the database — in a way that’s not platform-specific.

Any platform dependent implementation details — like cleaning up native resources — do use different fundamentals per-platform (Garbage Collector for Kotlin/JVM and the Cleaner API for Kotlin/Native). This is the type of feature that should be kept inside the Native Module Abstraction layer and not be implemented in the public library module.

By isolating these low level constructs in a separate Multiplatform module, we managed to scale the development of the new Kotlin SDK within the Realm team. All the low level building blocks are isolated behind an internal platform agnostic API. This also opens up API contributions from the community without worrying about the inherent complexity of C/C++, Kotlin/Native, or JNI.

Conclusion

Now, we’re proud to say that Realm’s engineering team managed to bootstrap the new Realm Kotlin SDK as a Multiplatform library. We believe that the infrastructure is in place to encourage other authors to build Multiplatform libraries, too.

Of course, as an alpha release, we’re still polishing elements of the solution. Realm engineering has been working in lockstep with the team at JetBrains, and we have full confidence that improvements will land soon.
As we keep working, we’d love your feedback. Try the new Realm Kotlin SDK out at https://github.com/realm/realm-kotlin, and join our discussion around the design of upcoming features here. We want your opinions and suggestions as we keep building.

Author: Nabil Hachica, Android Engineer, MongoDB Realm

Kite is an AI-powered programming assistant that helps you write code faster inside Visual Studio Code. Kite helps you write code faster by saving you keystrokes and showing you the right information at the right time.

Kite works for all major programming languages: Python, Java, Go, PHP, C/C#/C++, Javascript, HTML/CSS, Typescript, React, Ruby, Scala, Kotlin, Bash, Vue and React.

Features

Completions Powered by Machine Learning

Kite’s code completions are powered by machine learning models trained on over 25 million open-source code files. Kite also runs locally. Your code is private and does not leave your machine.

Instant Code Documentation

Get instant documentation for the symbol underneath your cursor so you save time searching for Python docs (not yet available for JavaScript docs).

Requirements

  • macOS 10.11+, Windows 7+ or Linux
  • Visual Studio Code v1.28.0+

Use another editor? Check out Kite’s other editor integrations.

Installation

Installing the Kite Engine

The Kite Engine needs to be installed in order for the package to work properly. The package itselfprovides the frontend that interfaces with the Kite Engine, which performs all the code analysis and machine learning 100% locally on your computer (no code is sent to a cloud server).

macOS Instructions

  1. Download the installer and open the downloaded .dmg file.
  2. Drag the Kite icon into the Applications folder.
  3. Run Kite.app to start the Kite Engine.

Windows Instructions

  1. Download the installer and run the downloaded .exe file.
  2. The installer should run the Kite Engine automatically after installation is complete.

Linux Instructions

  1. Visit https://kite.com/linux/ to install Kite.
  2. The installer should run the Kite Engine automatically after installation is complete.

Installing the Kite Plugin for Visual Studio Code

When running the Kite Engine for the first time, you'll be guided through a setup process which will allow you to installthe VS Code extension. You can also install or uninstall the VS Code extension at any time using the Kite Engine's pluginmanager.

Alternatively, you have 2 options to manually install the package:

  1. Search for 'Kite' in VS Code's built-in extension marketplace and install from there.
  2. Run the command code --install-extension kiteco.kite in your terminal.

Usage

The following is a brief guide to using Kite in its default configuration.

Autocompletions

Simply start typing in a saved Python or JavaScript file and Kite will automatically suggest completions for what you're typing. Kite's autocompletions are all labeled with the symbol.

Hover (Python only)

Vscode Kotlin Debug

Hover your mouse cursor over a symbol to view a short summary of what the symbol represents.

Documentation (Python only)

Click on the Docs link in the hover popup to open the documentation for the symbol inside the Copilot, Kite's standalonereference tool.

Definitions (Python only)

Visual Studio Kotlin

If a Def link is available in the hover popup, clicking on it will jump to the definition of the symbol.

Function Signatures (Python only)

When you call a function, Kite will show you the arguments required to call it. Kite's function signatures are also alllabeled with the symbol.

Note: If you have the Microsoft Python extension installed, Kite will not be able to show you information onfunction signatures.

Commands

Kite comes with sevaral commands that you can run from VS Code's command palette.

Visual Studio Code Kotlin Windows

CommandDescription
kite.related-code-from-fileSearch for code related to the current file in the Copilot
kite.related-code-from-lineSearch for code related to the current line in the Copilot
kite.open-copilotOpen the Copilot
kite.docs-at-cursorShow documentation of the symbol underneath your cursor in the Copilot
kite.engine-settingsOpen the settings for the Kite Engine
kite.python-tutorialOpen the Kite Python tutorial file
kite.javascript-tutorialOpen the Kite JavaScript tutorial file
kite.go-tutorialOpen the Kite Go tutorial file
kite.helpOpen Kite's help website in the browser

Troubleshooting

Visit our help docs for FAQs and troubleshooting support.

Happy coding!

About Kite

Visual Studio Kotlin

Kite is built by a team in San Francisco devoted to making programming easier and more enjoyable for all. Follow Kite onTwitter and get the latest news and programming tips on theKite Blog.Kite has been featured in Wired,VentureBeat,The Next Web, andTechCrunch.