Why Learning Scala Gave Me Déjà Vu of Kotlin: A Developer’s Journey

Kavya P S
8 min readJan 4, 2024

--

Imagine you’re 2 years deep into creating cool stuff with Kotlin for Android and you decide to venture into an unfamiliar territory — Backend development with Scala. You are all prepared to start from zero. But as you go on, it feels strangely familiar, like meeting an old friend. Let me take you through my journey — exploring Scala was a bit like déjà vu, reminding me of Kotlin in unexpected ways. Come along as I share this story of two coding worlds that seemed oddly similar to me!

Disclaimer:
Before I begin, I am only one day deep into Scala learning — okay 2–5 hours deep thanks to
this RockTheJVM tutorial!
So, this article is not a consolidated list, but a spoiler before you learn the basics of Scala
as a Kotlin developer (or vice versa).

Before we begin, here’s a “textbook” answer for similarities between Kotlin and Scala (thanks to ChatGPT) — feel free to skip it!

Kotlin and Scala, while having their unique features, share some similarities in their syntax. Here are a few key similarities between Kotlin and Scala:

1. Conciseness: Both Kotlin and Scala are designed to reduce boilerplate code, allowing developers to write more with less. They provide concise syntax for common operations, making the code cleaner and easier to read.
2. Type Inference: Both languages support type inference, allowing developers to omit explicit type declarations in many cases. The compiler can often deduce the types based on the context, reducing verbosity in code.
3. Functional Programming Features: Both languages incorporate functional programming concepts. They support higher-order functions, immutable data structures, lambda expressions, and various functional programming paradigms.
4. Null Safety: Kotlin and Scala provide features to handle null references safely. Kotlin has a robust system with nullable and non-nullable types, while Scala includes options like `Option` or `Some` to deal with null values.
5. Extension Functions/Methods: Both languages support extension functions/methods, allowing developers to extend the functionality of existing classes without directly modifying their code.
6. Pattern Matching: Scala and Kotlin offer pattern-matching constructs that enable developers to destructure data and perform operations based on the structure of objects, making code more expressive and concise.
7. Operator Overloading: Both languages allow operator overloading, enabling developers to define custom behaviors for operators (+, -, *, /, etc.) on their types.
8. Immutable Collections: Kotlin and Scala provide immutable collections as default or have robust support for creating immutable data structures, promoting safer and more predictable code.

While Kotlin and Scala share some similarities in syntax and concepts, they have their unique approaches and features that cater to different programming paradigms and ecosystems.

Now, here are a few specific syntax/concepts that gave me the Déjà Vu feeling as I was going through the YouTube playlist:

  • object | object
    (uhmmm… it’s the same keyword)
    Both Scala and Kotlin use the object keyword to define singleton instances, Scala's object is explicitly for creating singletons and encapsulating static-like members, while Kotlin's object not only creates singletons but also can be used to define anonymous objects with temporary or one-off behavior.

Scala:

object SingletonObject {
def doSomething() {
// Method implementation
}
}

Kotlin:

object SingletonObject {
fun doSomething() {
// Method implementation
}
}
  • def | fun
    (It’s safe to say Kotlin is “fun”)
    As you may have observed in the above example, def in Scala and fun in Kotlin are used to declare functions/methods, but they have differences in how they handle return types, expression vs. statement syntax, and implicit/explicit returns, reflecting the language-specific features and conventions of Scala and Kotlin.
  • extends | :
    (I guess coding in Kotlin is faster)

    While both languages have their way of indicating inheritance, Scala uses extends keyword explicitly in class declarations to inherit from a superclass while Kotlin uses a colon :.

Scala:

class Animal {
// Class definition
}

class Dog extends Animal {
// Dog class extending Animal
}

Kotlin:

open class Animal {
// Class definition
}

class Dog : Animal() {
// Dog class inheriting from Animal using colon syntax
}
  • multiple inheritance: (with separated) | (, separated)
    Scala allows classes to extend multiple traits using the with keyword, enabling a form of multiple inheritance, while Kotlin specifies the interface with a comma (,) separation.

Scala:

trait Flyable {
def fly(): Unit = println("Flying...")
}

trait Swimmable {
def swim(): Unit = println("Swimming...")
}

class Bird extends Flyable with Swimmable {
// Bird class inherits from Flyable and Swimmable traits
}

val bird = new Bird()
bird.fly() // Accessing method from Flyable trait
bird.swim() // Accessing method from Swimmable trait

Kotlin:

interface Flyable {
fun fly()
}

interface Swimmable {
fun swim()
}

class Bird : Flyable, Swimmable {
// Bird class implements Flyable and Swimmable interfaces
override fun fly() {
println("Flying...")
}

override fun swim() {
println("Swimming...")
}
}

val bird = Bird()
bird.fly() // Accessing method from Flyable interface
bird.swim() // Accessing method from Swimmable interface
  • Companion object | companion object

In Scala, a companion object is an object with the same name as a class, defined within the same file.

class MyClass {
// Class members

// Companion object
object CompanionObject {
// Companion object members
}
}

Similarly, in Kotlin, a companion object is an object declared inside a class with the companion keyword. It's used to define static-like behavior, including constants, factory methods, or shared methods, and can access private members of the class.

class MyClass {
// Class members

// Companion object
companion object {
// Companion object members
}
}
  • range | range
    Both provide constructs to represent ranges of values. Scala uses to and until methods to create ranges, while Kotlin uses the .. operator instead of to. While there are syntactical differences, both offer similar functionalities for iteration, checking inclusion, and working with ranges of values.

Scala:

val inclusiveRange = 1 to 5 // Represents the range from 1 to 5 (inclusive)
val exclusiveRange = 1 until 5 // Represents the range from 1 to 4 (excluding 5)

Kotlin:

val inclusiveRange = 1..5 // Represents the range from 1 to 5 (inclusive)
val exclusiveRange = 1 until 5 // Represents the range from 1 to 4 (excluding 5)
val charRange = 'a'..'z' // Represents the range of characters from 'a' to 'z'
  • interpolator string s | $
    Both Scala and Kotlin support string interpolation, Scala uses the s string interpolator and Kotlin uses the $ symbol to interpolate variables or expressions directly within string literals. Despite the syntax differences, the fundamental purpose of string interpolation remains the same in both languages—to embed dynamic values or expressions within strings for easier string manipulation.

Scala:

val name = "Alice"
val age = 30
val message = s"Hello, my name is $name and I am $age years old."

Kotlin:

val name = "Alice"
val age = 30
val message = "Hello, my name is $name and I am $age years old."
val message1 = "Hello, my name is $name and I am ${age + 20} years old."
  • Higher Order Functions

    Both Scala and Kotlin support higher-order functions, allowing functions to be treated as first-class citizens, passed as arguments or returned from other functions. While there are some syntactical differences (Eg: lambda syntax => in Scala and -> in Kotlin) the core idea of using functions as values remains consistent across both languages.

Scala:

def operate(numbers: List[Int], func: Int => Int): List[Int] = {
numbers.map(func) // Using map higher-order function
}

val addOne: Int => Int = (x: Int) => x + 1
val numbers = List(1, 2, 3, 4)
val result = operate(numbers, addOne) // Passing a function as an argument

Kotlin:

fun operate(numbers: List<Int>, func: (Int) -> Int): List<Int> {
return numbers.map(func) // Using map higher-order function
}

val addOne: (Int) -> Int = { x -> x + 1 }
val numbers = listOf(1, 2, 3, 4)
val result = operate(numbers, addOne) // Passing a function as an argument
  • lazy val | lazy
    (Potato… Po-tah-toh?)
    while Scala uses lazy val directly in its syntax to declare lazily initialized properties, Kotlin offers the lazy function from the standard library as an alternative for achieving lazy initialization of properties. Despite the syntax differences, both mechanisms allow for delayed computation until the value is accessed.

Scala:

class MyClass {
lazy val myLazyValue: Int = {
println("Initializing lazy value")
42
}
}

val obj = new MyClass()
println(obj.myLazyValue) // Initialization will occur here on the first access
println(obj.myLazyValue) // The value will be cached and reused without reinitialization

Kotlin:

class MyClass {
val myLazyValue: Int by lazy {
println("Initializing lazy value")
42
}
}

val obj = MyClass()
println(obj.myLazyValue) // Initialization will occur here on the first access
println(obj.myLazyValue) // The value will be cached and reused without reinitialization
  • Kotlin (to Scala): Your “Traits” are my “Interface”
    trait in Scala and interface in Kotlin serve as blueprints for defining common behavior and creating abstractions, facilitating code reuse, and promoting polymorphic behavior in their respective languages. While they share fundamental purposes, they have differences in their capabilities and how they are utilized within each language’s ecosystem.

Scala:

// Defining a trait in Scala
trait Printable {
def print(): Unit = println("Printing...")
}

// Using a trait in a class
class MyClass extends Printable {
// Other class implementations
}

Kotlin:

// Declaring an interface in Kotlin
interface Printable {
fun print() {
println("Printing...")
}
}

// Using an interface in a class
class MyClass : Printable {
// Other class implementations
}
  • Infix notation | Infix method:
    Both Scala’s infix notationand Kotlin’s infix functions allow methods or functions to be invoked using a more natural and readable syntax. They enable operations to be written in a way that resembles how they’re expressed in human language, enhancing code readability and expressiveness.

Scala:

// Defining a class with an infix method
class Calculator(val value: Int) {
// Infix method to add values
def +(other: Calculator): Calculator = new Calculator(value + other.value)
}

// Creating instances of the class
val calc1 = new Calculator(10)
val calc2 = new Calculator(5)

// Using infix notation for the method call
val result = calc1 + calc2 // Equivalent to calc1.+(calc2)

Kotlin:

// Declaring a class with an infix function
class Calculator(val value: Int) {
// Infix function to add values
infix fun add(other: Calculator): Calculator {
return Calculator(value + other.value)
}
}

// Creating instances of the class
val calc1 = Calculator(10)
val calc2 = Calculator(5)

// Using infix notation for the function call
val result = calc1 add calc2 // Equivalent to calc1.add(calc2)
  • Case classes | Data classes
    Case classes in Scala and Data classes in Kotlin serve similar purposes—they are used to create classes primarily meant to hold data, providing some built-in functionalities to reduce boilerplate code for creating immutable data-holding objects. However, there are differences in syntax, additional features, extensibility, and how they handle inheritance and component functions.

Scala:

// Defining a case class in Scala
case class Person(name: String, age: Int)

// Creating an instance of the case class
val person = Person("Alice", 30)
println(person.name) // Accessing properties directly

Kotlin:

// Declaring a data class in Kotlin
data class Person(val name: String, val age: Int)

// Creating an instance of the data class
val person = Person("Alice", 30)
println(person.name) // Accessing properties directly

That’s it!

Before you go, here’s an easy-to-remember representation, to help you keep a mental mapping as you learn Scala (being a Kotlin developer) or vice versa!

I suppose this is what you’d call a cheat sheet? :)

Happy learning!

--

--