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.
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?
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.
Top comments (7)
Great post, thanks!
One question about this Kotlin example:
Doesn't
location
need to belocation: String
, and doesn't there need to be a return type specified? Thanks.Acho que na última variável, do último exemplo, seria
Thanks! Fixed.
Super helpful! Thanks!
Very useful. I wish there was a book like Kotlin/Android for web developers, which goes straight to the point like this. In python, there is this similar book called "Python in a nutshell".
This is awesome mate :)
I really enjoyed your was article! Thanks for making the comparison between JS and Kotlin!