Swift vs Kotlin

Dan Meng
6 min readJul 18, 2022

--

This article is aiming to help an Android developer get a quick knowledge of the Swift programming language. (Writing from this perspective.)

I didn’t mean to write a very long and detailed article to cover everything, just a quick one to get you onboarded.

This article is also suitable for:

  • Experienced programmer (who knows other programming languages) wants to learn Swift.
  • iOS developer (who knows Swift) wants to learn Kotlin.
  • iOS beginner developers.
  • Developer hasn’t used Swift for a while and wants to get a quick refresher memo.

Basic types

Swift vs Kotlin: basic types
Swift vs Kotlin: basic types

Other types are basically the same.

Syntax

Swift vs Kotlin: Syntax

Constants and Variables

Swift:

  • let you can not assign value again. If the type is struct, you can not update any var properties of the instance. (If it's a class, then you can update var properties).
  • var can both assign values or update properties of the instance.
  • var also makes an array mutable.

Kotlin:

  • val means final in java, you can not assign values again, but you can update the public vars of the instance.
  • var means you can assign values again.
  • collections types’ immutable or mutable are controlled by the data type.

Switch case

Swift:

var x = 3
switch x {
case 1: print("x == 1")
case 2, 4: print("x == 2 or x == 4")
default: print("x is something else")
}

Kotlin:

val x = 3
when (x) {
1 -> print("x == 1")
2, 4 -> print("x == 2 or x == 4")
else -> print("x is something else")
}

String interpolation

Swift:

var name = "Mike"
print("Hello \(name)")

The string can also be output in a format:

let str = NSString(format:"%d , %f, %ld, %@", 1, 1.5, 100, "Hello World")
print(str)

Kotlin:

var name = "Mike"
println("Hello $name")

if you want to specify format:

val str = String.format("%d, %f, %d, %s", 1, 1.5, 100, "Hello World")
print(str)

Function and Closure

The Swift function has an argument label:

func someFunction(argumentLabel parameterName: Int) {
// In the function body, parameterName refers to the argument value
// for that parameter.
}

while parameterName is used inside the function, argumentLabel is used by the caller.

When an argument label is not provided, parameterName also plays the role of argumentLabel.

If you don’t want to specify an argument label at all, the argument label can be omitted by using underscored _.

Closure

Closure is similar to lambda in Kotlin.

A simple Swift example:

let sayHello = { (name: String) -> String in
let result = "Hello \(name)"
print(result)
return result
}
sayHello("Mike")

Do the same thing in Kotlin:

val sayHello : (String) -> String = { name: String -> 
val result = "Hello $name"
print(result)
result
}
sayHello("Mike")

Common:

  • The type can be inferred from the context.
  • Can be passed as arguments as another function’s parameter to achieve nested functions (high-order functions).
  • if the closure/lambda is the last parameter, we can put it outside the function’s parentheses. if it’s the only parameter, we don’t need to write parentheses().

Differences:

  • In Swift, only single expression closure can omitting the return keyword; In Kotlin, the last expression will be treated as the return value, no return keyword in lambda.
  • Swift has shorthand argument names such as $0, $1, $2.

Custom types

Swift vs Kotlin: custom types
Swift vs Kotlin: custom types

class

The class of Swift and Kotlin looks quite the same.

The inheritance is using : and the subclass function could override the super class's function.

There is an order requirement: the class need to be put before any protocols.

The only thing different is the constructor, in swift it’s initializer:

class Person {
let name: String
init(name: String = "") {
self.name = name
}
}
let p1 = Person()
print("\(p1.name)") // default name: ""
let p2 = Person(name: "haha")
print("\(p2.name)")

In Kotlin, we could achieve the same result by writing like this:

class Person(val name: String = "") {
}
val p1 = Person()
print("${p1.name}") // default name: ""
val p2 = Person(name="haha")
print("${p2.name}")

and in Kotlin, class can have an init {} block to help with more initializing work.

struct

Struct is value type.

struct vs class:

  • class can inherit.
  • struct is value type, copies never share data; class is reference type, all copies will share the same instance.
  • class has deinit.
  • class instance can be let , and you can change the var property of the class.
class Person {
var name = "Lily"
}
let p1 = Person()
p1.name = "Justin"
print("\(p1.name)")

This is ok.

But if Person is a struct:

struct Person {
var name = "Lily"
}
let p1 = Person()
p1.name = "Justin"
// Compiler error: Cannot assign to property: `p1` is a `let` constant

When using struct, we have to use **var** p1 = Person().

protocol

protocol is just like interface in Kotlin.

We could define function and properties as contracts.

The properties could be:

protocol SomeProtocol {
var mustBeSettable: Int { get set }
var doesNotNeedToBeSettable: Int { get }
}

There are slight differences in protocol and interface, like the class implementing the protocol doesn’t need to use the override keyword on functions.

extension

extension is also different. In Swift, extension is more like a place to hold the functions and properties.

extension String {
func trimmed() -> String {
self.trimmingCharacters(in: .whitespacesAndNewlines)
}

mutating func trim() {
self = self.trimmed()
}

var lines: [String] {
self.components(separatedBy: .newlines)
}
}

In Kotlin the extension method could be the top level method, just add the type before .:

fun String.someMethod() : String {
return this.trim()
}

enum

Swift enum:

enum CompassPoint {
case north
case south
case east
case west
}

Multiple cases can be put in one line, separated by comma:

enum Planet {
case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
}

When using the enum, we can drop the type using a shorter dot syntax:

var directionToHead = CompassPoint.west
directionToHead = .east

Swift enum has an allCases property, which exposes a collection of all the cases.

Kotlin:

enum class Direction {
NORTH, SOUTH, WEST, EAST
}

In enum we can also define properties and functions, which is the same for Swift and Kotlin.

Optionals

While the syntax of Swift’s optional type and Kotlin’s nullable type looks similar (a question mark following the type), they are different.

Swift’s optional type is more like Java’s Optional.

You will always need to unwrap it before using the value.

var someString : String? = nil
print(someString?.count) // print nil
print(someString!.count) // Fatal error: Unexpectedly found nil while unwrapping an Optional value

When the variable has value, we want to use it:

var someString : String? = "Hello"if (someString != nil) {
print("\(someString) with length \(someString?.count)")
// print: Optional("Hello") with length Optional(5)

print("\(someString!) with length \(someString!.count)")
// print: Hello with length 5
}

Note that when used directly, the variable will always be an Optional.

Actually in Swift there is a simpler way to do this, using if let:

if let someStringValue = someString {
print("\(someStringValue) with length \(someStringValue.count)")
}

The someStringValue is the unwrapped value from someString, and the block is only entered when it's not nil.

In Kotlin:

var someString : String? = null
print(someString?.length) // print null
print(someString!!.length) // NullPointerException

The difference is mainly when the variable has value:

var someString : String? = "Hello"
if(someString != null) {
print("$someString with length: ${someString.length}")
}
// print: Hello with length: 5

In Kotlin, after we check the variable is not null, we could use the value directly, in the following code inside {} , the compiler knows the variable is not null.

If let and guard let

As we see in the above sample in the Optional section, the if let can unwrap the Optional value, and only execute the block when it has value.

The guard let does the opposite: the else block will be entered only when the value is nil .

func printSquare(of number: Int?){
guard let number = number else {
print("Oops we got nil")
return
}

print("\(number) * \(number) is \(number * number)")
}

guard let can be used to do the argument checking and early return.

After the guard, the number is no longer optional, it has value.

Last note

I won’t suggest spending much time to learn a language syntax in every detail.

Just grab some basics and you are ready to go, you will explore more on your daily work.

Anyway, I hope this article is handy and useful to you.

References

--

--