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 2 of 4 of this article. Click here to view the first page.

Lambda Functions / Closures

Lambdas (Kotlin) and closures (Swift) are another useful building block in your coding arsenal. In essence, they are unnamed functions. They can be assigned to variables and passed around like any other value. The ability to treat functions as values is one of the functional programming aspects of Swift and Kotlin. Some common use cases for closures include handling asynchronous calls, for example, when making a network request and working with collections.

Kotlin — Lambda

Using a lambda:

val square = { a:Int ->
  a * a
}
println(square(4)) //16

The return type of a lambda is represented by a ->.

For lambdas with only one parameter, and whose type can be inferred, Kotlin provides a placeholder object name it for the parameter, and the -> can be eliminated, leading to a more concise syntax.

Calling a lambda using it:

var multiple: (Int) -> Int = { it * it }
println(multiple(4)) //16
multiple = {it * it * it} //don't need '->'
println(multiple(2)) //8

Swift — Closure

Using a closure:

var square = { (a: Int) -> Int in
  return a * a
}
print(square(4))

In Swift, the return type of a closure is also represented by a ->.

Just like Kotlin, this can be made more concise using a placeholder object; however, in Swift, you’re not just limited to a single parameter. $0 is the placeholder object name Swift gives to closure argument, where $0, $1 $2, etc., is used for each successive parameter. If you continue from the above example, in which the type of the variable square has already been established as an integer, you can rewrite your closure like this:

square = { //we can even omit the parameter list
  $0 * $0
}
print(square(3)) //9

Nullable / Optional Types

Both Kotlin and Swift are “safe” languages in that values can never be null / nil by accident — the programmer needs to deliberately use a special type of variable that can either have a value or no value at a given time of an application cycle. In Swift, these are known as “optionals” and, in Kotlin, they are called “nullable.” In both languages, they are represented by a ? placed to right of the variable type.

Kotlin — Nullable Type

var authToken: String? = "some long string"
authToken = null

Swift — Optional Type

var authToken: String? = "some long string"
authToken = nil

The syntax for declaring nullable in Kotlin and optional in Swift is exactly the same.

Handling a Nullable / Optional Type

To avoid crashes caused by trying to access a null value when it’s not expected, both languages have provided specific syntax for properly unwrapping nullable types. In both languages, it is not recommended to “force unwrap” an optional type (or using a not-null assertion for Kotlin’s nullable type) unless you’re 100% sure that your nullable variable will always have a value. Force unwrapping can be done using the exclamation sign ! in Swift and !! in Kotlin. Swift’s ! syntax serves as a warning in itself to the developer, and Kotlin takes it one step further!! See what we did there? :]

The following are a few ways to properly handle an optional / nullable type.

Kotlin — Null Safety

var id: Int? = 10
var userId = 0
if (id != null) {
 userId = id
} else {
 userId = -1
} 
println(userId) //prints 10

In the above piece of code, if id is equal to null, then userId will be assigned a value of -1.

In Kotlin, there’s an even more concise way to utilize null safety, via the Elvis Operator ?:

var id: Int? = null
val userId = id ?: -1 //userId is -1

The Elvis operator ensures that you get a value out of the nullable no matter what, by providing a default value in case a null value is encountered.

In the above example, using the Elvis operator means userId will equal either the value inside id, or -1 if id contains null.

Both Swift and Kotlin support conditional casting (referred to as “safe cast” in Kotlin), although in Swift it’s only applicable to downcasting to a subtype:

Kotlin

var practiceTime = (trombonePlayer as? Bandmember).practiceTime

Unlike Swift, in Kotlin, there is no guard statement. However, you can use the Elvis operator to similar effect.
Use what you learned earlier and combine the Elvis operator with a safe cast like so:

fun readyForParade (participant : Bandmember) : Boolean {
  val trombonePlayer = participant as?  Bandmember ?: return false
  return trombonePlayer. practiceTime > 6000
}

Here, if the value in the safe cast fails, readyForParade is null and the function will return without further execution.

Kotlin’s let function, when used in combination with the safe-call operator ?., provides a concise way to handle nullable expressions.

val userId = id.let { nonNullId -> nonNullId } ?: -1

Finally, Kotlin leverages a feature called smart casts, which combines type checks and casts. In Swift, you have the if let expression (see below), while, in Kotlin, you have smart casts. Kotlin’s smart casts seem a little bit “smarter,” while Swift’s if let is a little bit more clear when reading the code. Basically, in Kotlin once a nullable cast has been proven to be true (it’s not null, or the type is the correct type), for the rest of that scope the cast variable can be used directly without any further casts or additional syntax:

val id: Int? = null
if (id != null) {
  print(id) // id can be used directly in this scope
} else {
  print("id is null")
}

Contrast the above code with the if let Swift statement in the next section.

Swift – Optional Handling

Swift introduced the nil-coalescing operator in Swift 3, which works more or less like Kotlin’s Elvis operator.

let id: Int? = nil
var userId = id ?? -1 //prints -1

Swift uses the if let syntax alluded to earlier as the proper method for handling optionals, rather than force unwrapping:

let id: Int? = nil
if let userId = id {
  print(userId)
} else {
  print("userId is nil")
}

Swift uses the guard statement to provide an early exit to code execution. It provides clarity over if let by checking for the condition you want rather than the one you don’t, and by keeping the bulk of your important code from being nested inside of an if block.

Also, kind of approaching Kotlin’s smart cast mechanism, after a guard statement, any variables or constants that were assigned values using an optional binding as part of the condition are now available for the rest of the code block that the guard statement appears in. The guard statement requires a else condition which breaks out of the function.

func registerUser(userId: Int?) {
  guard let id = userId else { return }
  //do stuff with id
  id.description
}

Note that this isn’t quite the same as Kotlin’s smart cast mechanism — in this example, you couldn’t have written userId.description as userId still needs to be accessed as an optional.