The document discusses Kotlin Native and its interoperability with C/C++ and Swift. Some key points:
- Kotlin Native compiles Kotlin code to native binaries that run without a virtual machine on various platforms like iOS, MacOS, Android etc.
- It allows calling into existing native libraries written in C/C++/Swift and calling Kotlin Native code from other languages.
- Common data types like primitives, enums, structs can be mapped between Kotlin Native and C/C++. Kotlin Native supports pointers to interoperate with native code.
- Structs and other complex types are represented as classes in Kotlin Native but maintain the memory layout of the
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
ย
Kotlin Native - C / Swift Interop - ACCU Autmn 2019
1. training@instil.co
ACCU - November 2019
ยฉ Instil Software 2019
Interop Between Kotlin Native and C / Swift
The Good, the Bad and the Ugly @BoyleEamonn
Eamonn Boyle
@GarthGilmour
Garth Gilmour
7. 2010: Work begins on Kotlin within JetBrains
2011: First public announcement on Kotlin
2012: Open sourced under Apache 2 license
2016: Version one released
2017: First class support on Android
2018: Version 1.3 released
A Kotlin Timeline
11. If youโre working on the Java Virtual Machine, try not to use Java
Having done C# for many years I was so happy to see Kotlin for the JVM
Problems with Java
โข Verbose, Verbose, Verbose, Verbose, Verbose, Verbose, Verbose, Verbose,
โข Nulls
โข Completely OO
Why Kotlin - Java โ Yuck!
12. No need to wait - the interop story is so good
โข Call into all that legacy Java code easily
โข Call into your new Kotlin code from Java easily
Really concise, yet clear syntax
โข Less is more
โข โBorrowsโ the best bits of other languages
โข Less baggage
Why Kotlin โ So Much to Like
Null Safety
String Templates
Default parameters
Extensions
Free Functions
Coroutines
Single Expression Functions
Reified generics
Data classes and Properties
Type Inference
Smart Casts
Operator overloading
13. Basic Model Classes โ Java
public class Movie {
private String title;
private String description;
private Rating rating;
private Genre genre;
}
14. Basic Model Classes โ Java
public class Movie {
private String title;
private String description;
private Rating rating;
private Genre genre;
public Movie(String title, String description, Rating rating, Genre genre) {
this.title = title;
this.description = description;
this.rating = rating;
this.genre = genre;
}
}
15. Basic Model Classes โ Java
public class Movie {
private String title;
private String description;
private Rating rating;
private Genre genre;
public Movie(String title, String description, Rating rating, Genre genre) {
this.title = title;
this.description = description;
this.rating = rating;
this.genre = genre;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
16. Basic Model Classes โ Java
public class Movie {
private String title;
private String description;
private Rating rating;
private Genre genre;
public Movie(String title, String description, Rating rating, Genre genre) {
this.title = title;
this.description = description;
this.rating = rating;
this.genre = genre;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Rating getRating() {
return rating;
}
public void setRating(Rating rating) {
this.rating = rating;
}
public Genre getGenre() {
return genre;
}
public void setGenre(Genre genre) {
this.genre = genre;
}
}
17. Basic Model Classes โ Java vs Kotlin
public class Movie {
private String title;
private String description;
private Rating rating;
private Genre genre;
public Movie(String title, String description, Rating rating, Genre genre) {
this.title = title;
this.description = description;
this.rating = rating;
this.genre = genre;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Rating getRating() {
return rating;
}
public void setRating(Rating rating) {
this.rating = rating;
}
public Genre getGenre() {
return genre;
}
public void setGenre(Genre genre) {
this.genre = genre;
}
}
data class Movie(var title: String,
var description: String,
var rating: Rating,
var genre: Genre) {
}
Java Kotlin
18. Basic Model Classes โ Java vs Kotlin
import java.util.Objects;
public class Movie {
private String title;
private String description;
private Rating rating;
private Genre genre;
public Movie(String title, String description, Rating rating, Genre genre) {
this.title = title;
this.description = description;
this.rating = rating;
this.genre = genre;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Rating getRating() {
return rating;
}
public void setRating(Rating rating) {
this.rating = rating;
}
public Genre getGenre() {
return genre;
}
public void setGenre(Genre genre) {
this.genre = genre;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Movie movie = (Movie) o;
return Objects.equals(title, movie.title) &&
Objects.equals(description, movie.description) &&
Objects.equals(rating, movie.rating) &&
Objects.equals(genre, movie.genre);
}
@Override
public int hashCode() {
return Objects.hash(title, description, rating, genre);
}
@Override
public String toString() {
return "Movie{" +
"title='" + title + ''' +
", description='" + description + ''' +
", rating=" + rating +
", genre=" + genre +
'}';
}
}
data class Movie(var title: String,
var description: String,
var rating: Rating,
var genre: Genre) {
}
We also get hashCode(), equals(), toString() and moreโฆ
External libraries and tools like Lombok will help with Java
Java Kotlin
19.
20. Null Safety
private fun processUserPolicy(user: User) {
val policy = user.policy
if (policy.isComplete) {
policyProcessor.process(policy)
}
}
private static void processUserPolicy(User user) {
if (user != null && user.getPolicy() != null) {
Policy policy = user.getPolicy();
if (policy.isComplete()) {
policyProcessor.process(policy);
}
}
}
Java
Kotlin
21. Functional Chaining โ vs Java
Reified Generics with a single primitive representation makes the code simpler
double averageSalary = employees
.stream()
.filter(x ->
x.getDepartment() == Engineering)
.mapToInt(Employee::getSalary)
.average()
.orElse(0);
Java
val averageSalary = employees
.filter { it.department === Engineering }
.map { it.salary }
.average()
Kotlin
22. Kotlin was originally for writing server and desktop Java
โข Thatโs what JetBrains were building themselves
This evolved further into supporting Android
โข Which is now what itโs very popular for
JetBrains went further to support the Browser in Kotlin/JS and native in
Kotlin.Native
Kotlin Platforms
23. Kotlin/Native is a technology for compiling Kotlin code to native binaries
โข It runs without a virtual machine
โข The output is NOT portable
Although the binary output is not portable, the source IS portable
โข The compiler can compile the same source to multiple outputs/platforms
โข The source can be placed into a multiplatform project and used for JVM,
JS etc
Kotlin Native
Kotlin Compiler LLVMSource Native Binary
LLVM IR
24. Supported platforms include,
โข iOS (arm32, arm64, emulator x86_64)
โข MacOS (x86_64)
โข Android (arm32, arm64)
โข Windows (mingw x86_64)
โข Linux (x86_64, arm32, MIPS, MIPS little endian, Raspberry Pi)
โข WebAssembly (wasm32)
We can link to or dynamically call into other native libraries
โข C, Swift or ObjectiveC libraries
Note โ Kotlin/Native is still beta
Kotlin Native
26. You can drive everything from the command line
โข Kotlin Native CLI tools
โข Gradle for fully builder system
An IDE can make the whole experience much easier
IDEs
27. Common JVM APIs such as kotlin.io arenโt available
But there are multi-platform and native libraries that you can consume
Kotlin Native also supports excellent interop with C and ObjectiveC/Swift
API compatibility shown on doc pages
Supported APIs
import kotlinx.io.*
import kotlinx.cinterop.*
28. To simplify things further, common native APIs have already been wrapped
These bindings are platform specific but include
โข Posix
โข zlib
โข GDI (Windows)
โข OpenGL
โข Apple Frameworks
Platform Libraries
import platform.posix.*
29. A major reason for choosing Kotlin is that it is a great language
For Kotlin Native, the language remains unchanged
โข Though the implementation and runtime is wildly different
In native, it uses reference counting for automated memory management
โข And an additional cyclical garbage collector
Advantages of the Kotlin Language
30. Letโs have a look at native features and along the
way see some nice features of the language
generally
Advantages of the Kotlin Language
34. Data can be copied back and forth between Kotlin and C
โข Kotlin Native can automatically marshal from C primitive types
Primitive Types
C Kotlin
char kotlin.Byte
unsigned char kotlin.UByte
short kotlin.Short
unsigned short kotlin.UShort
int kotlin.Int
unsigned int kotlin.UInt
long long kotlin.Long
unsigned long long kotlin.ULong
float kotlin.Float
double kotlin.Double
35. If directly referencing C data, Kotlin Native uses a CVariable type
Internally, it contains a reference to C data via a NativePtr type
โข You can think of it a little like a wrapper or C++ reference or lvalue
CVariable
CVariable
NativePtr
0x02677dd0
Kotlin Native
0x0000000002677d00 00000000 00000000 581cbfec 7a7b0430 โ ยทยทยทยทยทยทยทยทXยทยทยทz{ยท0 โ
0x0000000002677d10 107d6702 00000000 587d6702 00000000 โ ยท}gยทยทยทยทยทX}gยทยทยทยทยท โ
0x0000000002677d20 abababab abababab abababab abababab โ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท โ
0x0000000002677d30 00000000 00000000 00000000 00000000 โ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท โ
0x0000000002677d40 eefeeefe eefeeefe 581cbfec 7b7b0430 โ ยทยทยทยทยทยทยทยทXยทยทยท{{ยท0 โ
0x0000000002677d50 0d000000 04080000 30aa4700 00000000 โ ยทยทยทยทยทยทยทยท0ยทGยทยทยทยทยท โ
0x0000000002677d60 abababab abababab abababab abababab โ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท โ
0x0000000002677d70 00000000 00000000 00000000 00000000 โ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท โ
0x0000000002677d80 00000000 00000000 581cbfec 7b7b0437 โ ยทยทยทยทยทยทยทยทXยทยทยท{{ยท7 โ
0x0000000002677d90 00000000 00000000 00ababab abababab โ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท โ
0x0000000002677da0 abababab abababab ab000000 00000000 โ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท โ
0x0000000002677db0 00000000 00000000 00000000 00000000 โ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท โ
0x0000000002677dc0 00000000 00000000 7c1cbccb 7b7b0400 โ ยทยทยทยทยทยทยทยท|ยทยทยท{{ยทยท โ
0x0000000002677dd0 b05f0201 00000000 e0200201 00000000 โ ยท_ยทยทยทยทยทยทยท ยทยทยทยทยทยท โ
0x0000000002677de0 eefeeefe eefeeefe eefeeefe eefeeefe โ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท โ
0x0000000002677df0 eefeeefe eefeeefe eefeeefe eefeeefe โ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท โ
36. There are CVariable types for,
โข All the primitives - IntVar, DoubleVar etc
โข Enums โ CEnumVar<T>
โข Structs โ CStructVar<T>
โข Pointers (more on this later) โ CPointerVar<T>
CVariables allow reading and writing via the value property
CVariable Types
fun sum(total: IntVar, current: Int) {
total.value += current
}
38. Structs can be easily created in C and mapped to Kotlin
โข The mapping is done automatically by including headers in the def file
Structs
class Employee(rawPtr: NativePtr) : CStructVar(rawPtr) {
companion object : Type(24, 8)
var name: CPointer<ByteVar>?
get() = memberAt<CPointerVar<ByteVar>>(0).value
set(value) { memberAt<CPointerVar<ByteVar>>(0).value = value }
var age: Int
get() = memberAt<IntVar>(8).value
set(value) { memberAt<IntVar>(8).value = value }
var salary: Double
get() = memberAt<DoubleVar>(16).value
set(value) { memberAt<DoubleVar>(16).value = value }
}
typedef struct {
char* name;
int age;
double salary;
} Employee;
39. The type name matches the C typedef but it is a CStructVar
Structs โ Points to Note
class Employee(rawPtr: NativePtr) : CStructVar(rawPtr) {
companion object : Type(24, 8)
...
}
typedef struct {
char* name;
int age;
double salary;
} Employee;
40. Internally it uses addresses to get CVariables but marshals into Kotlin types
Structs โ Points to Note
class Employee(rawPtr: NativePtr) : CStructVar(rawPtr) {
...
var age: Int
get() = memberAt<IntVar>(8).value
set(value) { memberAt<IntVar>(8).value = value }
var salary: Double
get() = memberAt<DoubleVar>(16).value
set(value) { memberAt<DoubleVar>(16).value = value }
} typedef struct {
char* name;
int age;
double salary;
} Employee;
41. Except where the returned type is a C type
โข E.g. pointers
Structs โ Points to Note
class Employee(rawPtr: NativePtr) : CStructVar(rawPtr) {
var name: CPointer<ByteVar>?
get() = memberAt<CPointerVar<ByteVar>>(0).value
set(value) { memberAt<CPointerVar<ByteVar>>(0).value = value }
...
}
typedef struct {
char* name;
int age;
double salary;
} Employee;
42. You will note that structs have a Type that includes size and alignment info
This facilitates allocation
Allocating Structs
class Employee(rawPtr: NativePtr)
: CStructVar(rawPtr) {
companion object : Type(24, 8)
...
}
typedef struct {
char* name;
int age;
double salary;
} Employee;
44. As well as CVariables, Kotlin Native supports pointers via CPointer<T>
The type of data pointed to, T, must be a CVariable type
โข Itโs actually CPointed which can be a CFunction, but more on that later
Pointers
Kotlin Native
0x0000000002677d00 00000000 00000000 581cbfec 7a7b0430 โ ยทยทยทยทยทยทยทยทXยทยทยทz{ยท0 โ
0x0000000002677d10 107d6702 00000000 587d6702 00000000 โ ยท}gยทยทยทยทยทX}gยทยทยทยทยท โ
0x0000000002677d20 abababab abababab abababab abababab โ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท โ
0x0000000002677d30 00000000 00000000 00000000 00000000 โ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท โ
0x0000000002677d40 eefeeefe eefeeefe 581cbfec 7b7b0430 โ ยทยทยทยทยทยทยทยทXยทยทยท{{ยท0 โ
0x0000000002677d50 0d000000 04080000 30aa4700 00000000 โ ยทยทยทยทยทยทยทยท0ยทGยทยทยทยทยท โ
0x0000000002677d60 abababab abababab abababab abababab โ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท โ
0x0000000002677d70 00000000 00000000 00000000 00000000 โ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท โ
0x0000000002677d80 00000000 00000000 581cbfec 7b7b0437 โ ยทยทยทยทยทยทยทยทXยทยทยท{{ยท7 โ
0x0000000002677d90 00000000 00000000 00ababab abababab โ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท โ
0x0000000002677da0 abababab abababab ab000000 00000000 โ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท โ
0x0000000002677db0 00000000 00000000 00000000 00000000 โ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท โ
0x0000000002677dc0 00000000 00000000 7c1cbccb 7b7b0400 โ ยทยทยทยทยทยทยทยท|ยทยทยท{{ยทยท โ
0x0000000002677dd0 b05f0201 00000000 e0200201 00000000 โ ยท_ยทยทยทยทยทยทยท ยทยทยทยทยทยท โ
0x0000000002677de0 eefeeefe eefeeefe eefeeefe eefeeefe โ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท โ
0x0000000002677df0 eefeeefe eefeeefe eefeeefe eefeeefe โ ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท โ
CPointer<T>
NativePtr
0x02677dd0
T = IntVar
45. The difference in CPointer and CVariable is subtle
โข They both contain an address/reference to some data in memory
โข The difference is similar to that between C++ references & C++ pointer
A CVariable facilitates reading and writing of typed data
โข Without considering pointers
A CPointer exposes the concept of a pointer for programmatic use
โข Passing around, dereferencing, operations etc.
CPointer & CVariable
46. Pointer parameters of C Functions are mapped to CValuesRef<T>
CValuesRef
fun sum(numbers: CValuesRef<IntVar>?, size: Int): Int
int sum(const int * numbers, int size)
47. This is designed to make passing Kotlin data to functions easier
We can create temporary copies of the data to be used only for the call
The data is copied to and lives in Kotlin space
โข This copying can be very expensive
A CPointer extends from a CValuesRef so it can be passed in directly
CValuesRef
CPointer<T>
CValuesRef<T>
CValues<T>
49. A Kotlin functionโs C type is a CFunction
It can be obtained by calling staticCFunction
It only works with unbound functions
โข So instance method references will not work (as they capture the object)
Lambda and static function references are both supported
Passing Kotlin Functions into C
CPointed
NativePointed
CVariable CFunction
51. To avoid common pitfalls of multi-threading with shared mutable state,
Kotlin imposes restrictions on how data can be shared between threads
Only one thread may own mutable data
โข Ownership can be transferred
Only immutable data or โfrozenโ data can be shared between threads
โข Any writes to frozen data results in an โInvalidMutabilityExceptionโ
Constraints in Sharing Data
Shared Mutable
XOR
โ
52. Only Frozen or Immutable data can be safely shared between threads
Singleton objects and enums are automatically frozen
Arbitrary objects can be frozen via the โfreezeโ method
Global variables can be marked with @SharedImmutable
Global variables can also be marked with @ThreadLocal
โข In which case each thread gets its own copy of the data
Freezing
53. These constraints apply to Kotlin data
โข Natively allocated data will not have these restrictions imposed
There are also atomic constructs which can be mutated
โข AtomicInt
โข AtomicDouble
โข Etc
Obviously, if using these constructs then you have all the potential pitfalls
โข Race conditions, deadlocks etc
Breaking the Rules
55. A good ecosystem is essential for rapid development
As a lot of Kotlin code is multi-platform by default, many libraries can be
consumed by Kotlin Native
โข Sometimes only partially support
A good example of this is the coroutines library
Using Libraries
56. โCoroutines are computer-program components
that generalize subroutines for non-preemptive
multitasking, by allowing multiple entry points
for suspending and resuming execution at
certain locations.โ
Wikipedia
Coroutine
59. Consider 3 independent jobs of work
Event Loop with Asynchronous Blocks
Start 5 6EndBlocking Start 5 6EndBlocking Start 5 6EndBlocking
Start 5 6EndBlocking
Start 5 6EndBlocking
Start 5 6EndBlocking
If we want to run these in parallel we could create multiple threads
60. Asynchronous Use Case โ Thread Pools
Start End
Blocking
Start End
Blocking
Start 5 6End
Blocking
64. Swift itself is not supported but Objective C is supported
Swift APIs can be exported to Objective C by annotating with @objc
Bidirectional interop with Objective C is more intuitive & complete than C
โข Classes and interfaces/protocols can be used
โข Reference counting and garbage collection are integrated
โข More types are automatically mapped e.g. List
Objective C & Swift Interop
65. We will focus on the interop story with Swift rather than Objective C directly
โข It is a more modern language and the obvious choice for new development
Since Swift is translated to Objective C, we immediately lose features
โข Generics
โข Tuples
โข Enumerations defined in Swift without Int raw value type
โข Structures defined in Swift
โข Top-level functions and global variables defined in Swift
โข Typealiases defined in Swift
โข Swift-style variadics
โข Nested types
โข Curried functions
Objective C & Swift Interop
66. We can also compile Kotlin into Apple frameworks and libraries
Under this scenario we do not have support for,
โข Suspend functions
โข Inline classes
But many things map intuitively
Objective C & Swift Interop
67. Note that for elements to get translated, they must be,
โข Annotated with @objc
โข Public within a public class
Translations
@objc
public class Employee : NSObject {
@objc public let name: String
@objc public var age: Int
@objc public var salary: Double
public let noObjC = ""
@objc let notPublic = ""
open class Employee : NSObject {
@ObjCMethod("name", "@16@0:8")
external open fun name(): String
@ObjCMethod("age", "q16@0:8")
external open fun age(): NSInteger
@ObjCMethod("setAge:", "v24@0:8q16")
external open fun setAge(age: NSInteger): Unit
@ObjCMethod("salary", "d16@0:8")
external open fun salary(): Double
@ObjCMethod("setSalary:", "v24@0:8d16")
external open fun setSalary(salary: Double): Unit
// ...
68. Mappings
Kotlin Swift Objective-C
class class @interface
interface protocol @protocol
constructor/create Initializer Initializer
Property Property Property
Method Method Method
@Throws throws error:(NSError**)error
Extension Extension Category member
companion member <- Class method or property Class method or property
null nil nil
Singleton Singleton() [Singleton singleton]
69. Kotlin Swift Objective-C
Primitive type Primitive type / NSNumber
Unit return type Void void
String String NSString
String NSMutableString NSMutableString
List Array NSArray
MutableList NSMutableArray NSMutableArray
Set Set NSSet
MutableSet NSMutableSet NSMutableSet
Map Dictionary NSDictionary
MutableMap NSMutableDictionary NSMutableDictionary
Function type Function type Block pointer type
Mapping
70. Function types also have good support including closures
Note that primitive parameters will be boxed
Type differences may cause function reference issues
โข E.g. Expecting an a Long parameter for an Int parameter
Function Types
@objc
public func filter(numbers: [Int], predicate: (Int) -> Bool) -> [Int]
external open fun filter(numbers: List<*>,
predicate: (NSInteger) -> Boolean): List<*>
Swift
Kotlin
72. C++ interop is not there, only via C
Swift interop is good but not fully there
โข Since it is translating via Objective C
Build times are slow - especially when compared with modern languages
โข E.g. Kotlin/Java on JVM, TypeScript, C#
The Bad
73. Still beta so there are some issues
โข In Windows the IDE keeps locking the klib so I need to restart
โข Autocomplete not in CLion for Gradle KTS
โข Documentation incomplete or out of date
Encountered memory leak that I couldnโt quite track down
The Bad
74. With C, you will need to switch between Strings and pointers to Byte
โข It will depend on the usage case
โข E.g. function calls, struct fields, function pointers
You miss some of the features of the Java Standard Library
โข Posix give some cross platform features but โฆ
โข There are differences in the APIs across platforms
โข They are not Kotlin first so the usage is clunky
Performance is not there
โข Generally when compared with say a JVM implementation
โข CValues can have severe performance impact
The Bad
75. The Kotlin language is excellent so using in more environments is good
The tooling around code authoring is excellent
โข Though documentation and debugging is not there yet
Interop with C and Objective C is fairly good
โข Especially Swift/Objective C with memory management, closures etc.
The potential for sharing code across platforms is appealing
The Good
76. Kotlin is spreading
โข The right balance between simplicity and productivity
โข Easy interoperation with Java
Kotlin/Native is very interesting
โข Still beta but JetBrains are working hard
โข Provides a solution for iOS support
Summary
77. A good set of libraries allows you to be productive
โข Kotlin/Native doesnโt have thatโฆyet
โข The interop and wrapping of other libraries will be key
โข First class support of more Kotlin libraries will be key
Kotlin, soon to be the write once, run anywhere language
Summary
Wellโฆ.maybe