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.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
A Comparison of Swift and Kotlin Languages
30 mins
- Understanding Similarities Between Swift and Kotlin
- Declaring Properties
- Kotlin — Mutable Properties
- Swift – Mutable Properties
- Kotlin — Immutable Properties
- Swift — Immutable Properties
- Data Structures
- Arrays
- Dictionaries / Maps
- Functions
- Lambda Functions / Closures
- Nullable / Optional Types
- Handling a Nullable / Optional Type
- Control Flow
- Classes
- Class Extensions
- Interface / Protocol
- Functional Programming Tools
- Understanding Differences Between Swift and Kotlin
- Where to Go From Here?
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.