Skip to content

kotlin-hands-on/kotlin-swift-interopedia

 
 

Repository files navigation

official JetBrains project

Kotlin-Swift interopedia

Introduction

Kotlin/Native provides bidirectional interoperability with Objective-C. At the time of writing, Kotlin is not directly interoperable with Swift but rather indirectly via an Objective-C bridge. Swift export is something that the Kotlin/Native team intends to address in future. However, the reason for choosing to start with Objective-C is sound: older projects containing Objective-C code can also call shared Kotlin code, along with projects containing Swift code.

In general, the basics of the Kotlin language such as classes, properties, and functions can be easily used from Swift. However, some other language features may not be as readily used. This interoperability encyclopedia (or “interopedia”) aims to explain how shared Kotlin code using various language features can be called from Swift. When there is no straightforward way to do so, we discuss workarounds and library solutions, if available.

In order to provide the best possible experience for Swift developers, the rule of thumb is that using the simplest language features is best. Kotlin developers may not be expert Swift developers as well, so collaboration with their Swift teammates is required so that Kotlin developers can create shared Kotlin APIs that can be called in a beautifully idiomatic way.

How to use

Interopedia

This interopedia of the different Kotlin language features is categorized into broad categories, namely:

  • Overview
  • Functions and properties
  • More about functions
  • Types
  • Classes and interfaces
  • Coroutines
  • Extensions
  • Generics

Each language feature has its own article, consisting of an explanation of the feature, some sample code in Kotlin, how to call this code from Swift (if possible), and additional improvements should the Swift code not be as idiomatic as we’d like.

You could search the interopedia for the particular language feature that you are interested in, or read all the articles in order for a more comprehensive understanding of Kotlin/Swift interoperability.

Kotlin/Swift Interop Playground app

The iOS app is organized into the same broad categories as the interopedia. Clicking on a specific language feature will:

  • Display a summary of the interoperability of the feature.
  • Run code samples associated with the feature and print the results in the console.

You can edit the code, rerun the app, and see how the output has changed.

Overview

Classes and functionsYou can instantiate Kotlin classes and call Kotlin functions from Swift: SimpleClass().simpleFunction().
Top-level functionsYou can access a top-level function via the wrapper class: TopLevelFunctionKt.topLevelFunction().
TypesSimple types and custom types can be passed as arguments and returned from function calls.
CollectionsKotlin and Swift have very similar kinds of collections and can be mapped between each other.
ExceptionsIf you invoke a Kotlin function that throws an exception and doesn't declare it with `@Throws`, that crashes the app. Declared exceptions are converted to NSError and must be handled.
Public APIPublic classes, functions, and properties are visible from Swift. Marking classes, functions, and properties internal will exclude them from the public API of the shared code, and they will not be visible in Swift.
Interop annotation - @ObjCNameGives better Objective-C/Swift names to Kotlin constructs like classes, functions and so on, without actually renaming the Kotlin constructs. Experimental.
Interop annotations - @HiddenFromObjHides a Kotlin declaration from Objective-C/Swift. Experimental.
Interop annotations - @ShouldRefineInSwiftHelps to replace a Kotlin declaration with a wrapper written in Swift. Experimental.
KDoc commentsYou can see certain KDoc comments at development time. In Xcode, use Option+Double left click to see the docs. Note that many KDocs features don't work in Xcode, like properties on constructors (@property) aren't visible. In Fleet, use the 'Show Documentation' action.

Functions and properties

Member functionsYou can call public member functions from Swift. Internal or private declarations aren't visible.
ConstructorYou call constructors to create Kotlin classes from Swift.
Read-only member propertiesMember val property is accessible from Swift and is a read-only property in Swift.
Mutable member propertiesMember var property is accessible from Swift and is a mutable property in Swift.
Top-level val properties (readonly)You access a top-level property via the wrapper class: TopLevelPropertyKt.topLevelProperty.
Top-level var properties (mutable)You access a top-level property via the wrapper class: TopLevelMutablePropertyKt.topLevelProperty.
Functions expecting lambda argumentsYou can use a function expecting one or more lambdas as arguments without issues from Swift.
Functions returning function typeYou can call a Kotlin function returning a lambda. The result has Swift function type, like () -> String, so you can easily call it.

More about functions

Functions with overloadsThere are some peculiarities when using the same parameter names.
Functions with default argumentsYou always have to specify all the function arguments. Improved interop available with SKIE.
Constructor with default argumentsYou always have to specify all the arguments for a constructor.
Functions expecting lambda with receiverThe extension function turns into a lambda with a parameter.
Functions with receiversFunctions with receivers turn into functions with parameters, which is not as convenient.
Functions with value class parameterThe function appears in the .h file, but the inline class argument is turned into a basic type.
Functions with vararg parametervarargs are mapped to KotlinArray, not Swift's variardic parameters.
Inline functionsInline functions are in the .h file, they can be called. However, they are regular functions and not inlined.

Types

Basic typesMay require mapping for integer data types and mapping for Char.
Optional basic typesSome basic types require mapping into special optional types.
Collections with custom typesCollections with elements of custom types do not require additional mappings.
Collections with basic typesCollections with elements of basic types (except String) require a wrapper.
Mutable, immutable collectionsTo adjust mutability, the let and var keywords are used. Additional mappings are required for mutable collections.
Unit and NothingThe Unit and Nothing types can be used in the same way as in Kotlin: Unit as an object or void, Nothing cannot be created.

Classes and interfaces

Abstract classesXcode has no hints to override abstract methods, rather we get a crash when trying to use the method during runtime.
Annotation classesAnnotations are not supported and are not included in the .h file.
Data classesSome autogenerated functions are converted to Swift: copy to doCopy, equals to isEquals, toString to description. Additional features, like destructuring, are not supported.
Enum classesNo equivalent enum is generated on the Swift side, and default case must be specified in a switch expression. Instead an object with static elements is generated. Improved interop available with SKIE.
Inner classesMinor differences in creation syntax.
Open classesCan inherit from open class, use its protected properties, override open, but not override final methods.
Sealed classesA class with heirs is generated. Passing to a switch statement requires a default case. Improved interop available with SKIE.
Inline classesThis feature is not supported.
ObjectsYou can access Kotlin object via the shared auxiliary object: MyKotlinObject.shared.myProperty.
Companion objectsYou can access members of Kotlin companion objects from Swift explicitly through the `companion` auxiliary object: ClassWithCompanionObject.companion.CONST_VAL_EXAMPLE.
Fun interfacesYou can't create an anonymous class in Swift.
InterfacesThe interface has become @protocol. Xcode turns val property into var when generating the stubs.
Sealed interfacesSeparate protocols are generated that are not related to each other.

Coroutines

Suspend functionsTranslated into callback, experimentally - into async / await. Libraries like SKIE and KMP-NativeCoroutines can be used to improve the interop and provide cancellation support.
FlowsTranslated into callback, experimentally - into async / await. Generic type arguments are lost. Libraries like SKIE and KMP-NativeCoroutines can be used to improve the interop and provide cancellation support.

Extensions

Extension function over platform classA wrapper class appears with a function that accepts an object of the desired class.
Extension function over usual classThe function can be used on a class object.
Extension properties over platform classA wrapper class appears with a function that accepts an object of the desired class.
Extension properties over usual classThe property can be accessed through the class object.
Extension properties for companion object of platform classThere is a property in the .h file, but in Swift it’s impossible to use.
Extension properties for companion object of usual classThe property can be accessed through the companion object.

Generics

Generic classesSome features are supported.
Generic functionsAutomatic type inference and nullability are not supported.
Bounded genericsThe generic type restriction is not supported.
Contravariant genericsRequires a type cast.
Covariant genericsRequires a type cast.
Reified functionsThe reified function crashes at runtime.
Star projectionRequires a type cast.
Generic interfacesGeneric interfaces are not supported.

Releases

No releases published

Packages

No packages published

Languages

  • Swift 72.0%
  • Kotlin 28.0%