loading...

Kotlin for JS Devs (Part 1)

cassiozen profile image Cássio Souza ・9 min read

JavaScript is an amazing language: It came from being a “toy language” when it was introduced, into the most ubiquitous programming language out there — you can run it on the browser, on servers, you can build a mobile app, a wearable app — heck, you can program the Nasa SpaceSuite using JavaScript.

Node in Spacesuite

Still, there are opportunities in learning more than one language — and I’m not even talking about career opportunities: As David Thomas and Andrew Hunt say in their classic book “The pragmatic programmer”:

Learn at least one new language every year. Different languages solve the same problems in different ways. By learning several different approaches, you can help broaden your thinking and avoid getting stuck in a rut.

In short: Yeah, JavaScript is amazing but learning a new language is a powerful thing: it affects the way you think about programming, gives you new perspectives and impacts the way you solve problems, ultimately making you a better software developer.

Ok, but why Kotlin?

Why Kotlin

There are hundreds of programming languages out there, so why Kotlin? Well, Kotlin is soaring in popularity (and demand); it’s loved by its users and is attracting a horde of JavaScript developers. And that’s not me saying: GitHub’s state of octoverse report points Kotlin as the fastest growing language on it’s platform, the “State of Kotlin” report shows that JavaScript developers are the second biggest “source” of new Kotlin developers. Finally, the love for the language is captured in the “Stack Overflow inside” report.

Fancy facts aside, Kotlin has a lot of characteristics that makes it a great candidate for your next language:

  • It has a modern syntax: Elegant, concise and straightforward — you can focus on getting things done.
  • It understands that Object Orientation and functional programming are not competing, but orthogonal paradigms, and adopts both (in this case, it actually shares similarities with JavaScript).
  • It’s the official language for Android development with many libraries, extensions and optimizations available.
  • It is multiplatform — Kotlin’s main target is the JVM (Java Virtual Machine — for both client and server applications), but you can compile it to JavaScript to use on the web or down to native binary (e.g. windows, linux, iOS and Mac libraries)

Last but not least, it's fun to use.

Quick language reference (from JS to Kotlin)

Over the next few sections, you will have an overall, birds-eye view of the Kotlin language syntax and semantics compared side-by-side with JavaScript. Of course, with new syntax and semantics, new patterns and ways of building things arise, but let’s not focus on those (or other Kotlin details) so far — the best way to learn a new language is to get playing with it quickly so you can be ready for more in no time (and in time for the next article in this series =]).


Variables and Constants

Kotlin variables are declared with the var keyword. To prevent reassignment, you can use val — both works much like JavaScript’s let and const.

Kotlin is a typed language, which means that in some cases you will have to add type annotations in your code. Most of the time, though, the compiler can infer the type automatically:

JavaScript

const name = "Jon Snow";
let isAlive = true;
let role; // Declared but not initialized

Kotlin

// Types can be inferred from initialized variables
val name = "Jon Snow"
var isAlive = true

// If the variable is declared but not initialized, a type annotation is required:
var role: String


Strings

Single and Multiple line strings

JavaScript

const house = "Stark";
const motto = `
Winter
is
comming
`;

Kotlin

val house = "Stark"
val motto = """
Winter
is
comming
"""

String Interpolation

JavaScript

const action = `Attacking using a ${weapon}`;

const result = `Looks like you will ${user.getFate()}`;

Kotlin

const action = "Attacking using a $weapon" 

const result = "Looks like you will ${user.getFate()}" // curly brackets are only necessary to interpolate expressions


Functions

Named Functions

Functions in Kotlin are declared using the fun keyword. You need to add type annotations for each parameter and also for the function return type.

JavaScript

function double(num) {
    return num * 2;
}
double(2); // 4


// Default values
function shout(message, postfix = "!!!") {
    return `${message.toUpperCase()}${postfix}`;
}
shout("hey"); // HEY!!!

Kotlin

fun double(num:Int) {
    return num * 2
}

// Default values
fun shout(message: String, postfix = "!!!"): String {
    return "${message.toUpperCase()}$postfix"
}

Named Parameters

In Kotlin, function parameters can be named when calling functions. This is very convenient when a function has a high number of parameters or default ones.

Kotlin

fun reformat(str: String,
             normalizeCase: Boolean = true,
             upperCaseFirstLetter: Boolean = true,
             divideByCamelHumps: Boolean = false,
             wordSeparator: Char = ' ') {
    ... 
}

reformat("SomeString", normalizeCase = false, divideByCamelHumps = true)

Function expressions (Lambdas)

Lambda expressions are "function literals", i.e. functions that are not declared, but passed immediately as an expression. In JavaScript they are commonly called “arrow functions”, and in kotlin, “lambdas”.

In Kotlin, A lambda expression is always surrounded by curly braces, parameter declarations in the full syntactic form go inside curly braces and have optional type annotations, the body goes after a -> sign. Note: You can’t specify a return type for lambdas in Kotlin. In most cases, this is unnecessary as it can be inferred automatically.

JavaScript

const double = (num) => num * 2; // Single line has implicit return

const square = (num) => {
    const result = num * num;
    return result; // Multi line: No implicit return
}

Kotlin

val double = { num:Int -> num * 2 }

val square = { num: Int -> 
    val result = num * num
    // The last expression in a lambda is always considered the return value:
    result
}

It’s very common that a lambda expression has only one parameter. As a convenience, Kotlin gives special treatment to those and automatically declares the single parameter under the name it:

JavaScript

const carModels = cars.map((car) => car.model );
const oldEnough = users.filter((user) => user.age >= 21 );

Kotlin

val carModels = cars.map { it.model }
val oldEnought = users.filter { it.age >= 21 }

Flow Control

if/else

JavaScript

if (number > 0) {
    console.log("Positive number");
} else {
    console.log("Negative number");
}

Kotlin

if (number > 0) {
    print("Positive number")
} else {
    print("Negative number")
}

Unlike JavaScript (and many other programming languages), if is an expression in Kotlin - it returns a value:

JavaScript

let result;
if (number > 0) {
    result = "Positive number";
} else {
    result = "Negative number";
}

Kotlin

val result = if (number > 0) {
    "Positive number"
} else {
    "Negative number"
}

In Kotlin, you can leave the curly braces out if you’re writing in one line — therefore there is no ternary operator:

JavaScript

const result = number > 0 ? "Positive number" : "Negative number";

Kotlin

val result = if (number > 0) "Positive number" else "Negative number"

Switch (When)

Kotlin has a when construct that can be thought of as a replacement for JavaScript switch Statement:

JavaScript

switch (selectedFruit) {
  case "orange":
    console.log("Oranges are 59 cents a pound.");
    break;
  case "apple":
    console.log("Apples are 32 cents a pound.");
    break;
  case "cherry":
    console.log("Cherries are one dollar a pound.");
    break;
  case "mango":
  case "papaya":
    console.log("Mangoes and papayas are 3 dollars a pound.");
    break;
  default:
    console.log(`Sorry, we are out of ${selectedFruit}.`);
}

Kotlin

when(selectedFruit) {
    "orange" -> print("Oranges are 59 cents a pound.")
    "apple" -> print("Apples are 32 cents a pound.")
    "cherry" -> print("Cherries are one dollar a pound.")
    "mango", "papaya" -> print("Mangoes and papayas are 3 dollars a pound.")
    else -> print("Sorry, we are out of $selectedFruit.")
}

In reality, Kotlin's when is much more powerful than this, and many people describe it as "Switch with superpowers". Here are some when advantages:

  • it can be used as an expression
  • it can have arbitrary condition expressions
  • it can cast the value automatically
  • it can be used without an argument
  • it can be used to require exhaustiveness (all possible conditions needs to be matched)

I will not dive deeper in Kotlin's when in this article, but it's important to know that it can be tremendously useful in your code. When you feel ready, refer to this other article to learn more.


Loops

Kotlin does provide a for loop, but it only works with iterators (like Lists and Maps). Fortunately Kotlin also provides ranges, iterators which can be created using the .. operator:

JavaScript

for (let i = 1; i<=10; i++) {
    console.log(i);
}
// 1 2 3 4 5 6 7 8 9 10


const places = ["New York", "Paris", "Rio"];
for (const place of places) {
  console.log(`I Love ${place}`);
}
// I Love New York 
// I Love Paris
// I Love Rio

Kotlin

for (i in 1..10) {
    print(i)
}
// 1 2 3 4 5 6 7 8 9 10


val places = listOf("New York", "Paris", "Rio")
for (place in places) {
    println("I Love $place")
}
// I Love New York 
// I Love Paris
// I Love Rio

Collections

Kotlin doesn’t provide collection literals (such as [] for arrays or {} for objects). Instead, it provides global functions that can be used to create collections. The reasoning behind this decision is that when language provides collection literal, it influences how uses will use the collections (and by extension, the way people use the language itself). Mutable vs Immutable, List vs Array - Kotlin gives freedom of choice to the user.

Arrays (in this case meaning “lists of stuff that can grow dynamically…”)

“Array” is an overloaded term that can mean different things in different programming languages — and that’s exactly the case with Kotlin: It does have Arrays, but they’re not comparable to JavaScript Arrays (that is, they’re not lists that can grow or shrink dynamically). In this case, the more comparable collection is a List:

JavaScript

const houses = [ "Stark", "Lannister", "Tyrell", "Arryn", "Targaryen", "Baratheon" ];
houses[2]; // "Tyrell"
houses.push("Martell");
houses.length; //7

Kotlin

val houses = mutableListOf("Stark", "Lannister", "Tyrell", "Arryn", "Targaryen", "Martell", "Baratheon")
houses[2] // "Tyrell"
houses.add("Martell")
houses.size //7

Objects (in this case meaning “key-value maps”)

Objects in JavaScript serves many purposes: It’s a hashmap, but it’s also the base construct from which everything (except primitives) are descended (not to mention that it’s also the place where you find utility methods such as Object.assign). Since we're talking about collections, I'm illustrating the hashmap use case (storing key-value pairs).

JavaScript

const colors = {
  "red":  0xff0000,
  "green":  0x00ff00,
  "blue":  0x0000ff,
  "cyan":  0x00ffff,
  "magenta":  0xff00ff,
  "yellow":  0xffff00
};
colors.hasOwnProperty("yellow"); // true
colors.yellow; // 0xffff00

Kotlin

val colors =  mutableMapOf(
  "red" to 0xff0000,
  "green" to 0x00ff00,
  "blue" to 0x0000ff,
  "cyan" to 0x00ffff,
  "magenta" to 0xff00ff,
  "yellow" to 0xffff00
)
colors.contains("yellow") // true
colors.get("yellow") // 0xffff00

A quick note on Immutability

Kotlin also provides provides read-only versions of its collections:

Kotlin

// mapOf is the read-only version of mutableMapof
val colors =  mapOf(
  "red" to 0xff0000,
  "green" to 0x00ff00,
  "blue" to 0x0000ff
)
val updatedColors = colors.plus("teal" to 0x008080) // doesn't change the original - it returns a new map


// listOf is the read-only version of mutableListof
val houses = listOf("Stark", "Lannister", "Tyrell", "Arryn", "Targaryen", "Martell", "Baratheon")

// Methods that return a new list instead of modifying it are still available:
var updatedHouses = houses.take(3).map {it.toUpperCase()} //["STARK", "LANNISTER", "TYRELL"]

// Adding new items requires copying the whole original one and making sure the new copy is also immutable
var updatedHouses = houses.toMutableList().apply{ add("Martell") }.toList()

Destructuring Assignment

Destructuring declaration syntax can be very handy and save you a few lines of code: when you assign a collection to a value, Kotlin breaks up and match the sides against each other, assigning the values on the right to the variables on the left. In the simplest case, it can be used for parallel assignment:

JavaScript

const coordinates = [5, 10, 15];
const [x, y, z] = coordinates;

Kotlin

val coordinates = arrayOf(5, 10, 15)
val (x, y, z) = coordinates

While the example above can look silly, this is especially convenient for dealing with functions that return multiple values:

JavaScript

function weatherReport(location) {
  // Make an Ajax request to fetch the weather...
  return [72, "Mostly Sunny"];
}
const [temp, forecast] = weatherReport("Berkeley, CA");

Kotlin

fun weatherReport(location) {
  // Make an Ajax request to fetch the weather...
  return Pair(72, "Mostly Sunny") // Pair is a standard class in Kotlin that represents a generic pair of two values
}
val (temp, forecast) = weatherReport("Berkeley, CA")

Classes

Much like in JavaScript, classes in Kotlin are declared using the keyword class:

JavaScript

class Monster {
  constructor(name, color, numEyes) {
    this.name = name;
    this.color = color;
    this.numEyes = numEyes;
  }
  speak(likes) {
      return `My name is ${this.name} and I like ${likes}`;
  }
}
var nhama = new Monster("Nhama", "red", 1);
nhama.speak("guacamole")
// "My name is Nhama and I like guacamole"

Kotlin

class Monster(val name: String, val color: String, val numEyes: Int) {
  fun speak(likes: String):String {
      return "My name is $name and I like $likes"
  }
}
var nhama = Monster("Nhama", "red", 1)
// Kotlin doesn't have a `new` keyword - you instantiate a class by calling it directly
nhama.speak("guacamole")
// "My name is Nhama and I like guacamole"

Kotlin classes also have a constructor, but the keyword can be omitted if all you want to do is define class properties.


Data Containers

In JavaScript, it is common place to create plain Objects to group named values together. In Kotlin, you will want to create a Data Class — they also act as data containers but are lighter, have fixed field names and are a bit more rigidly typed.

JavaScript

const movie1 = {
    name: "Back to the Future",
    rating: 5,
    director: "Bob Zemeckis"
}
const movie2 = {
    name: "Star Wars: Episode IV - A New Hope",
    rating: 5,
    director: "George Lucas"
}

Kotlin

data class Movie(
  val name: String, 
  val rating: Int, 
  val director: String
)
val movie1 = Movie("Back to the Future", 5, "Bob Zemeckis")
val movie2 = Movie("Star Wars: Episode IV - A New Hope", 5, "George Lucas")

Where to go from here?

Throughout this article, the Kotlin syntax was always contrasted to JavaScript's syntax - There are, however, a few areas where Kotlin have unique approaches that draw no parallel with JavaScript - The most prominent example is Kotlin’s approach to nullability. On the Part 2 of this article, I will cover some of Kotlin's unique features: null safety and asynchronous programming - see you soon.

Discussion

markdown guide
 

Acho que na última variável, do último exemplo, seria


movie2
 
 
 

I really enjoyed your was article! Thanks for making the comparison between JS and Kotlin!