Posted in Kotlin, Scala

Scala vs Kotlin

It’s been a long time since I’ve updated this blog. Over the year I’ve moved away from Scala as my preferred language and towards Kotlin. I’ve found Kotlin a refreshing approach as its borrowed a lot of the good things I liked about Scala but kept it simple and practical by avoiding a lot of the gotchas and ambiguity that can exist in Scala.

Here is a collection of things I like about Scala and Kotlin and also a comparison of how these features are accomplished in each language.

Type Declaration and Inference

Something I love about both these languages is they both have static typing with type inference. This gives you the power of compile time type checking with out the declarative boiler plate. Largely it works the same in both languages. Both languages also have preference to immutable type declaration as well with the optional type declaration being placed after the variable name.

Example, the below code is the same in both languages:

Declare a immutable variable named age of type Int:

val age = 1

Declare a mutable variable of type String:

var greeting = "Hello"

Both languages support lambda functions as first class citizens that can be assigned to variables or passed as function parameters.

Scala:

val double = (i: Int) => { i * 2 }

Kotlin:

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

Data / Case Class

Both Scala and Kotlin have a similar concept of a data class which can be use to represent a data model object.

Scala’s Approach

Scala calls this a case class and it can be defined like:

case class Person(name: String, age: Int)

This gives you the following main advantages over a normal class:

  • Has an apply method (You don’t need to use the ‘new’ word to construct instances)
  • Accessor methods are defined for each property (If property are defined as var then setters are also defined)
  • toString, equal and hashCode is sensibly defined
  • copy function
  • Has an unapply method (which allows use in match expressions)

Kotlin’s Approach

Kotlin calls this a data class and it’s defined like:

data class Person(val name: String, val age: Int)

Key Features

  • Accessor methods are defined for each property (If property are defined as var then setters are also defined). This is not unique to data class and works on any class in Kotlin.
  • Sensibly defined toString, equal and hashCode
  • copy function
  • component1..componentN functions. Similar use to unapply.
  • Implements JavaBean getter and setters defined so native Java frameworks (Hibernate, Jackson) without change

Kotlin doesn’t need a special ‘apply’ method as it doesn’t require a ‘new’ keyword to instantiate class constructors. So this is a standard constructor definition like any other class.

Comparison

Generally data and case classes are similar.

This example usage works the same in Kotlin or Scala:

val jack = Person("Jack", 1)
val olderJack = jack.copy(age = 2)

Generally I’ve found data and case classes interchangeable in day to day use. Kotlin does enforce some restriction on extending a data class with inheritance but its done for good reasons when you consider the implementations of equals and componentN functions and prevents the gotcha moments.

The Scala case classes can be more powerful in a match statements compared to Kotlin’s handling of data classes in ‘when’ statements which is something I miss.

Kotlin approach works a lot better when being used from existing Java frameworks as it will look like a normal java bean.

Both languages support supplying parameters by name and allow for default values.

Null Safety / Optionality

Scala’s Approach

Scala’s approach to null safety is the option monad. Simply an option can be one of two concrete types; Some(x) or None.

val anOptionInt: Option[Int] = Some(1)

OR

val anOptionInt: Option[Int] = None

You can operate on the option using functions on the option class like “isDefined” and “getOrElse” (to provide a default value) but more commonly you would use monad operations like map, foreach or fold which will treat the option as a collection containing 0 or 1 elements.

For example to sum two Optionally defined Ints you could do:

val n1Option: Option[Int] = Some(1)
val n2Option: Option[Int] = Some(2)
val sum = for (n1 <- n1Option; n2 <- n2Option) yield { n1 + n2 }

The variable sum will have the value Some(3). This is leveraging Scala’s for comprehension which can be foreach or a flat map function depending on the use of the yield keyword.

Another example of chaining could be:

case class Person(name: String, age: Option[Int])
val person:Option[Person] = Some(Person("Jack",Some(1)))
for (p <- person; age <- p.age) {
 println(s"The person is aged $age")
}

This will print “The person is aged 1”

Kotlin’s Approach

Kotlin’s approach borrows from groovy style syntax and is very practical in every day use. In Kotlin all types are non-nullable and must be explicitly declared nullable using ‘?’ if it can contain null.

The same example could be written

val n1: Int? = 1
val n2: Int? = 2
val sum = if (n1 != null && n2 != null) n1 + n2 else null

This is much closer to Java syntax except Kotlin will enforce compile time checks so its not possible to use a nullable variable without checking it is not null first so you won’t fear NullPointerExceptions. Its also not possible to assign a null to a variable declared as non-nullable. The compiler is quite smart in checking branch logic so you don’t have the situation of over guarding that you see in Java where the same variable is checked for null multiple times.

An equivalent Kotlin code for the second example of chaining is:

data class Person(val name: String, val age: Int?)
val person:Person? = Person("Jack", 1)
if (person?.age != null) {
  println("The person is aged ${person?.age}")
}

An alternative is also available using “let” which could replace the if block with

person?.age?.let {
  println("The person is aged $it")
}

Comparison

I really prefer the Kotlin approach. It’s a lot easier to read and understand what’s going on and multiple levels of nesting is easy to handle. The scala approach has symmetry in that other monads can be acted on the same as option can (e.g. futures) which some people like but I’ve found it can get complicated really fast once there is a little bit of nesting. There are also a lot of gotcha’s with for comprehension as under the covers they are maps or flat maps but you don’t get the compile time warnings if you do something wrong like mix monads or do a pattern match without covering alternative paths which leads to runtime exceptions that are cryptic.

Kotlin’s approach also bridges the gap when integrating with Java code as they can default to nullable types where as Scala still has to support null as a concept without null safety protection.

Functional Collections

Scala of course supports many functional goodies. Kotlin is a little more restrictive but the basics are covered.

There isn’t much difference in the basic fold and map functions.

Scala

val numbers = 1 to 10
val doubles = numbers.map {_ * 2}
val sumOfSquares = doubles.fold(0) {_ + _}

Kotlin

val numbers = 1..10
val doubles = numbers.map {it * 2}
val sumOfSquares = doubles.fold(0) {x,y -> x+y}

Both support the concept of lazy evaluated sequences. For example printing first 10 even squares.

Scala

val numbers = Stream.from(1) // all natural numbers
val squares = numbers.map {x => x * x}
val evenSquares = squares.filter {_%2 == 0}
println(evenSquares.take(10).toList)

Kotlin

val numbers = sequence(1) {it + 1} // all natural numbers
val squares = numbers.map {it * it}
val evenSquares = squares.filter {it%2 == 0}
println(evenSquares.take(10).toList())

Implicits Conversion vs Extension Functions

This is an area where Scala and Kotlin diverge a little.

Scala’s Approach

Scala has a a concept of implicit conversion that allows you to add extra behaviour to a class by automatically converting to another class when needed. An example of this

object Helpers {
 implicit class IntWithTimes(x: Int) {
   def times[A](f: => A): Unit = {
    for (i <- 1 to x) {
     f
    }
  }
 }
}

Then later in the code you can do:

import Helpers._
5.times(println("Hello"))

This will print “Hello” 5 times. How this works is when you try to use the “times” function which doesn’t exist on the Int the object will be automatically boxed into an IntWithTimes object and the times function will executed on that.

Kotlin’s Approach

Kotlin has the concept of extension functions that can be used to accomplish a similar job. In the Kotlin approach you define a normal function but prefix the function name with a type to extend.

fun Int.times(f: ()->Unit) {
  for (i in 1..this) {
    f()
  }
}

5.times {println("Hello")}

Comparison

Kotlin approach fits the use case that I generally would use this Scala capability for and has the advantage of being a little simpler to understand.

Scala Features Not Present in Kotlin that I won’t Miss

One of the best part of the Kotlin language for me is not the features it has but more the features from Scala that are not in Kotlin

  • Call by name – This destroys readability. If a function is being passed its a lot easier when its visible that its a function pointer in a basic review of the code. I don’t see any advantage this gives over passing explicit lambdas
  • Implicit parameters – This is something I’ve really hated. It leads to situation of code changing drastically based on a change of import statement. It makes it really hard to tell what values will be passed to a function without good IDE support
  • Overloaded FOR comprehension – To me this is a clunk to get around the problem with dealing with multiple monads
  • The mess with optional syntax on infix and postfix operators – Kotlin is little more prescriptive and means that the code is less ambiguous to read and not as easy for simple typo to become a non-obvious error
  •  Operator Overload to the Max – Kotlin allows basic operator overloads for the basic operators (+, – etc.) but Scala allows any bunch of characters to be used and it seems to have been embraced by library developers. Am I really meant to remember difference between “~%#>” and “~+#>”?
  • Slow compile times
Advertisements

11 thoughts on “Scala vs Kotlin

  1. I disagree in a few respects.

    Call-by-name — I think it has some syntax advantages, but specifically I find it nice for writing DSLs. I used to use lambdas as you suggest, but found in some situations that creating the lambdas actually came off feeling really unnatural/disruptive (i.e. I called the function with values far more often than computed values).

    Implicits — sure they can make a mess, but they enable ad hoc polymorphism (the type-class pattern), without which real functional style becomes nearly impossible.

    ‘for {}’ — It’s just syntantic sugar over map and flatMap, which are obviously useful. It doesn’t care if your objects are monadic or not. Also keep in mind that Scala has a REPL, and is used for data science quite a bit. Writing a messy set of chained functions, or predefining every operation you’re going to do with a method before you use it, would kill productivity.

    I do agree about the operators, i can’t keep them straight either, but that’s more of a library thing.

    Like

    1. Sure there are definite positives but there are nicer ways to do this. Kotlin still has pretty good support for DSL type approaches if you look at things like https://kotlinlang.org/docs/reference/type-safe-builders.html

      The thing I don’t like about implicits is they are brought in by imports that could be local or global. In most languages I’ve used, imports are just used for name scoping so you don’t have to qualify the package or class every time but in Scala it can change the functionality of the code so you have to check the imports when you review chunks of code and you need to know the signatures of functions. It’s impossible to do this without a good IDE. I’m still a bit torn on this, I do like implicit conversion and do find I use implicits a lot. I do love to be able to say 1.minute (using the implicit conversions for Int to Duration as an example) but this can accomplished with extension functions in Kotlin. I also do rely on implicit parameters like executioncontext for futures but I would prefer a better way even if I have to be more explicit.

      Some problems with “for” is that you can actually do something like “for(Some(x) <- myOption)" which doesn't account for None as an option and this becomes a runtime exception, not a compile time. Also you can do "for(x<-myOption; n<-myList)" which of course won't work because this translates to flatmap and that doesn't make sense between an option and a collection.

      Like

  2. Except implicits, which I hate too, none of the other differences matter.
    – “optional syntax on infix and postfix operators”? Who’s stopping you from being explicit?
    – “Scala allows any bunch of characters to be used” How’s that any worse than a method named “doIt” or “execute” in Java or Kotlin?

    I’m not saying Scala is the best thing since sliced bread, it has it’s cons. But I’ve yet to see any clear advantages that warrant moving to a whole new language. Until then, to me, Kotlin is a fad not unlike Clojure and “this, too, shall pass”.

    Like

  3. Congratulations on the article, it really gave me somewhat of an overview of kotlin compared to scala that I was looking for.

    One thing that really left a dent on it was when you mentioned the call by name as somewhat unnecessary. Not having call by name as a tool can seriously limit a language capabilities in more complex implementations, especially when performance is the goal.

    Like

    1. The main issue I have with it is code readability and easily picking up mistakes. If you were reviewing some code and saw a call like this “printMe5Times(expensiveCompute())”, it won’t be evident easily to the reviewer that the expensive compute is actually going to be executed 5 times instead of just the result printed 5 times. If you force use of lambda style syntax like “printMe5Times({expensiveCompute()})” or “printMe5Times { expensiveCompute() }” then it’s a bit more obvious that you don’t want the expensiveCompute function inside the functional block.

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s