# Kotlin Talk Notes
## What is Kotlin?
Kotlin is a programming language created by JetBrains (the people behind IntelliJ and many other awesome IDEs). Kotlin can target the JVM, Android, JavaScript (for the browser!), and native desktop. For our purposes, you can think of it like the Android equivalent to Swift for iOS development.
It is super easy to setup and use, is 100% interoperable with Java, and has a lot of really nice language features that Java is sorely lacking.
> Kotlin makes Android development bearable, and actually fun.

If you need one reason to try Kotlin, look at these side-by-side examples of data classes (POJOs) in Java and Kotlin:

## Kotlin is "safer" than Java
Personally, I love Kotlin's syntax. But the BIGGEST reason to use Kotlin in my opinion is that Kotlin's type system is more strict.
Kotlin distinguishes between **nullable** and **non-null** types. This can identify potential null values at compile time and force you to deal with them, preventing a lot of NullPointerExceptions.
This is valid Java
```java=
String str = "foo";
str = null;
Int len = str.length; // NullPointerException! Your app crashed!
```
The same code in Kotlin does not compile
```kotlin=
var str: String = "foo"
str = null // Compile error! Much better!
```
To allow nulls, you must declare your variable to be _nullable_
```kotlin=
var str: String? = "foo"
str = null
```
Then, to access any String properties on `str`, you first need to verify that it is not null. You can do this easily using _safe calls_. If you have used Swift, these might look similar to Optional types.
```kotlin=
val len = str.length // Compile error! str might be null
val len = str?.length // This compiles. NOTE: The type of len is Int?, not Int.
```
## Some of my favorite things about Kotlin syntax
### Types go _after_ variable names, instead of before
I don't know why, but languages where the type goes before the variable have always bothered me.
```java=
public Int sum(Int a, Int b) {
return a + b;
}
```
In Kotlin, this looks like:
```kotlin=
fun sum(a: Int, b: Int): Int {
return a + b;
}
```
### One-liner functions
Just like JavaScript arrow functions, you can write Kotlin functions with a single expression body instead of a block with a `return` statement.
```kotlin=
fun sum(a: Int, b: Int): Int {
return a + b;
}
// The same function can be written like this:
fun sum(a: Int, b: Int) = a + b
```
### String templates
This is pretty standard in any modern language. Kotlin automatically calls `toString()` on anything in a template expression.
```kotlin=
val name = "Ian"
val greeting = "Hello, $name"
val duh = "One plus one is ${1 + 1}"
```
### The `when` expression
Pattern matching is awesome! It's like a switch statement, but way better.
```kotlin=
var x = 3
when (x) {
1 -> print("x is 1")
2 -> print("x is 2")
3, 4 -> print("x is 3 or 4")
// The condition of a when expression can be any expression that evaluates to a boolean
in 5..10 -> print("x is in the range [5, 10]")
else -> print("x is out of range")
}
```
Kotlin forces you to handle _every possible case_ in a `when` expression. This makes your code safer.
```kotlin=
enum class CallState {
Initializing,
Connecting,
Connected,
Disconnecting,
Disconnected
}
val currentState = CallState.Connecting
val message = when (currentState) {
CallState.Initializing -> "Your call is initializing..."
// Missing one...
CallState.Connected -> "You are connected!"
CallState.Disconnecting -> "The call is disconnecting..."
CallState.Disconnected -> "The call is over!"
}
// The above code does not compile. Kotlin knows that `currentState` might be a value other than the ones handled here. You must either add a case for every value, or add a `else` case.
```
### Lambdas
Kotlin has lambdas. These are basically like
```kotlin=
// A lambda with full explicit types
val sum: (Int, Int) -> Int = { x: Int, y: Int -> x + y }
// A lambda without type annotations
val sum = { x, y -> x + y }
// For a lambda with a single argument, You can omit the `->`. In that case, the argument
// will implicitly be called `it`
val isGreaterThanZero = { it > 0 }
```
Using lambdas looks like this:
```kotlin=
var strings = ["a", "bb", "ccc", "dddd", "eeeee", "ffffff", "ggggggg"]
var longStrings = strings.filter({ str -> str.length > 5 })
```
If a function takes a lambda as its _last_ parameter, you can put the lambda outside of the parentheses. This results in some really cool, weird syntax:
```kotlin=
var longStrings = strings.filter {
it.length > 5
}
```
This feature lets you write code that looks like its own mini-language within Kotlin. Check out this snippet of UI code from a Kotlin library called Anko:
```kotlin=
// These are actually nested function calls. Awesome!
verticalLayout {
padding = dip(30)
editText {
hint = “Name”
textSize = 24f
}
editText {
hint = “Password”
textSize = 24f
}
button(“Login”) {
textSize = 26f
}
}
```
### Extension Functions
You can use extension functions to add functionality to existing classes. I find this to be really helpful when dealing with third-party libraries.
```kotlin=
fun String.replaceSpaces(): String {
return this.replace(' ', '_')
}
val str = "Hello world!"
val formatted = str.replaceSpaces() // "Hello_world!"
```
### Operator Overloading
```kotlin=
data class Vec(val x: Float, val y: Float) {
operator fun plus(v: Vec) = Vec(x + v.x, y + v.y)
}
val v = Vec(2f, 3f) + Vec(4f, 1f)
```
## How does Kotlin work with React Native?
Because Kotlin is interoperable with Java, there's no reason you can't have the native parts of your React Native app entirely in Kotlin. Even your `MainActivity` and `MainApplication`.
> NOTE: I don't advise writing the `MainApplication` in Kotlin, since `react-native link` assumes your code is Java, and will say it can't find the file and auto-update it for you. If you are on RN > 0.60, this isn't a problem anymore.
I'm going to walk through creating a pure-Kotlin Android native module
### Step 1: Add Kotlin standard lib to build.gradle
```groovy=
// Project-level build.gradle
buildscript {
ext {
kotlinVersion = '1.3.11'
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${project.ext.kotlinVersion}"
}
}
// App-level build.gradle
apply plugin: 'kotlin-android'
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk:${project.ext.kotlinVersion}"
}
```
### Step 2: Create the native package
```kotlin=
// Skipping import statements
class SofiaCallPackage : ReactPackage {
override fun createNativeModules(reactContext: ReactApplicationContext): MutableList<NativeModule> {
return mutableListOf(SofiaCallModule(reactContext))
}
override fun createViewManagers(reactContext: ReactApplicationContext): MutableList<ViewManager<View, ReactShadowNode<*>>> {
return mutableListOf()
}
}
```
### Step 3: Create the native module
```kotlin=
// Skipping import statements
class SofiaCallModule(val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
// Anything in a companion object is equivalent to "static" in Java
companion object {
const val RN_MODULE_NAME = "SofiaCall"
const val TAG = "SofiaCallModule"
const val ACCEPT_CALL_ACTION = "onAcceptCall"
const val REJECT_CALL_ACTION = "onRejectCall"
}
// Rather than constructors, you can have any number of `init` blocks in your class that execute from top-to-bottom when an instance of this class is created.
init {
val intentFilter = IntentFilter()
intentFilter.addAction(ACCEPT_CALL_ACTION)
intentFilter.addAction(REJECT_CALL_ACTION)
LocalBroadcastManager.getInstance(reactContext).registerReceiver(CallBroadcastReceiver(), intentFilter)
}
// Static values, one-liner functions, and overrides, all in one line! Sweet!
override fun getName() = RN_MODULE_NAME
// This method will be callable from JavaScript due to the annotation
// This method displays a notification that launches the app when a call is received
@ReactMethod
fun displayIncomingCallNotification() {
val pendingIntent = createAppIntent(Intent.ACTION_MAIN)
val builder = NotificationCompat.Builder(reactContext, "${reactContext.packageName}-Videoconsultas").apply {
setOngoing(true)
priority = Notification.PRIORITY_HIGH
setContentIntent(pendingIntent)
setAutoCancel(true)
setFullScreenIntent(pendingIntent, true)
setSmallIcon(R.mipmap.ic_launcher)
setContentTitle("TODO: Incoming call title")
setContentText("TODO: Incoming call text")
val acceptIntent = createAppIntent(ACCEPT_CALL_ACTION)
val rejectIntent = createAppIntent(REJECT_CALL_ACTION)
// TODO: Add proper drawable resources for these buttons
addAction(R.mipmap.ic_launcher, "Accept", acceptIntent)
addAction(R.mipmap.ic_launcher, "Reject", rejectIntent)
}
val notification = builder.build()
notification.flags += Notification.FLAG_INSISTENT
val notificationManager = NotificationManagerCompat.from(reactContext)
notificationManager.notify(1001, notification)
}
```