A Comparison of Swift and Kotlin Languages

This article focuses on the main similarities and differences between Swift and Kotlin, including implementation, style, syntax and other important details. By Aaqib Hussain.

Leave a rating/review
Save for later
Share
You are currently viewing page 3 of 4 of this article. Click here to view the first page.

Control Flow

Just as functions and closures are the building blocks of any app, if-else, switch, for loops and other types of control flow are the logical glue that enable applications to work.

Kotlin — if-else

If-else statements work in Kotlin similar to most other languages:

if (a > b) {
 println("Choose a")
} else {
 println("Choose b")
} 

Swift — if-else

One cool feature in Swift is that parentheses () around the condition are also optional. I’m just wondering how long it will take for Kotlin to adopt this feature. ;]

if a > b {
  print("Choose a")
} else {
  print("Choose b")
} 

Kotlin — when

when is the name given to switch statements in Kotlin.

val x = 3
when (x) {
  1 -> println("x == 1")
  2 -> println("x == 2")
else -> { 
  print("x is neither 1 nor 2")
  }
}

Swift – switch

let x = 3
switch x {
  case 1:
    print("x == 1")
  case 2:
    print("x == 2")
  default:
    print("x is neither 1 nor 2")
}

Note that in Swift, a switch statement must be exhaustive. In other words, a default clause is required if every single possible value of the condition hasn’t been tested. This is not the case in Kotlin; so for switch statements Swift is actually more clear and less prone to programmer errors. On the other hand, the syntax for switch statements in Kotlin is more concise. In both languages, the statement returns as soon as the first matching condition is evaluated, so there is no need for a break statement.

Kotlin — for loop

There are a number of ways of writing loops in Kotlin.

val days = arrayOf("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")
for (day in days) {
  println(day)
}

for loop using the range operator:

for (item in 1..10) {
  println(item)
}

In this example the .. specifies an inclusive range; the numbers 1 – 10 are printed. Both Kotlin and Swift provide a variety of different types of range operators.

Swift – for loop

let days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
for day in days {
  print(day)
}

Using another type of range operator, in Swift:

for item in 1..<10 {
  print(item)
}

Classes

Declaring a class in both languages is almost the same:

Kotlin - Class

class MainActivity: AppCompatActivity() {

}

Swift - Class

class ViewController: UIViewController {

}

What are known as "constructors" in Kotlin are "initializers" in Swift. Kotlin also has an init block that is paired with a constructor.

Kotlin - Constructor

class Car constructor(_model: String) {
  val model: String

  init {
    model = _model
  }
}

Swift - Initializer

public class Car {
  let model: String

  init(model: String) {
    self.model = model
  }
}

Class Extensions

Class extensions are a cool feature adopted by modern languages. It helps in extending the functionality of existing classes.

Kotlin - Extension

Consider extending the Int class with a function that returns a square of an integer:

fun Int.square(): Int {
  return this * this
}

println(5.square()) //prints 25

Swift - Extension

extension Int {
  func square() -> Int {
    return self * self
  }
}

print(5.square()) //prints 25

Interface / Protocol

What is known as an interface in Kotlin, and other languages, is called a protocol in Swift. It helps you maintain a decoupled codebase, achieve polymorphism, and write mocks for testing.

Kotlin — Interface

In Kotlin an interface declaration looks just like the declaration of a class:

interface Animal {
  var canFly: Boolean 

  fun eat()

  fun makeSound()
}

Swift - Protocol

protocol Animal {
  var canFly: Bool {get}

  func eat()

  func makeSound()
}

An interface / protocol can also have a default implementation. Default behavior remains the same whenever that function is called without being overridden. Assume you want the property canFly to be false in all conditions until or unless its required to change.

Kotlin - Default Implementation

interface Animal {
  val canFly: Boolean 

  get() = true 
}

Swift — Default Implementation

Extensions are used to give protocols default implementations:

protocol Animal {
  var canFly: Bool {get}
}

extension Animal {
  var canFly: Bool {
    return false
  }
}

Functional Programming Tools

These new languages come packed with powerful tools that enable you to write code using a functional paradigm. There are lots of tools provided by them, but have a look at just a few of them.

map

map is used for transforming data into a new form.

Kotlin - map

Consider a data class Person, containing properties name and date of birth.


data class Person(var name: String, var dob: String)

Note: In Kotlin a Data Class is similar to a class, but with the sole purpose of holding data. It makes your code more concise and you don't have to write an initializer. Data classes are a powerful way in Kotlin to implement "value objects".

Note: In Kotlin a Data Class is similar to a class, but with the sole purpose of holding data. It makes your code more concise and you don't have to write an initializer. Data classes are a powerful way in Kotlin to implement "value objects".

Now, consider a list containing few objects of type Person:

val persons = listOf(Person("Jon", "12 August"),
  Person("Kim", "10 July"),
  Person("Vanessa", "12 August"),
  Person("Alisa", "26 March"), null)

You might be wondering why I assigned a null to the end of the list? Assigning a list with a null is not required. Sit tight! you'll have your answer soon enough. :]

Say you want to get the names of all the persons into a separate list — that's where you'll use the map function to help you.


val names = persons.map { it?.name } //Jon, Kim, Vanessa, Alisa, null

Swift — map

Similarly, in Swift consider a Person struct:

struct Person { 
  let name: String
  let dob: String 

  init(name: String, dob: String) {
    self.name = name
    self.dob = dob
  }
}

And an array of persons:

let persons = [Person(name: "Jon", dob: "12 August"),
  Person(name: "Kim", dob: "10 July"),
  Person(name: "Vanessa", dob: "12 August"),
  Person(name: "Alisa", dob: "26 March"), nil]

To transform the persons array into a names array:

let names = persons.map { $0?.name } //Jon, Kim, Vanessa, Alisa, nil

filterNotNull & compactMap

To remove null / nil objects from an array:

Kotlin - filterNotNull

//returns List<Person> instead of List<Person?>
val nonNullPersons = persons.filterNotNull() 

Swift - compactMap

compactMap is similar to the map function, but it returns all the non-nil objects.

//returns [Person] instead of [Person?]
let nonNullPersons = persons.compactMap{$0} 

Filter
Instead of iterating through an array or list with a loop, the filter function can be used to filter for the desired values.

Filter the array having the date of birth as "12 August."

Kotlin - filter

val personWithSameDOB = persons.filter { it?.dob == "12 August" } 

Swift - filter

let personWithSameDOB = persons.filter { $0?.dob == "12 August" }