28

A Comparison of Swift and Kotlin Languages [FREE]

 5 years ago
source link: https://www.tuicool.com/articles/hit/fYFBvyU
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Swift and Kotlin have taken the developer community by storm, helping to increase the number of developers for both platforms. Both languages rapidly gained adoption due to their easy syntax, simple way of writing and the modern techniques and features they bring to the table.

Swift first appeared in June 2, 2014, and was developed by Apple to work with the Cocoa Touch framework. It works on top of the LLVM, an open source collection of compilers and toolchains . Swift has been a part of Xcode since version 6 was released. Apple open sourced Swift on December 3, 2015. Swift can be mixed with Objective-C in projects, but is meant to replace Objective-C.

Initially, Kotlin was developed by a group of developers from Saint Petersburg, Russia, working at the company JetBrains. Kotlin was publicly unveiled in 2011. Kotlin runs on the JVM and is designed to interoperate seamlessly with Java, and is meant as a replacement for Java. Google announced official support for Kotlin as a development language for Android in 2017. Kotlin rolled out with Android Studio 3.0 in October 2017.

In this article, you will take a tour of Swift and Kotlin and how they compare. While there is no hands-on tutorial, reviewing these language elements will provide you a great overview that will expand your knowledge of both of these languages. This tutorial assumes you have a basic understanding of either Swift or Kotlin.

Understanding Similarities Between Swift and Kotlin

Swift and Kotlin are incredibly similar to one another. If you’d like to try out any of the following code snippets below for yourself, you can do so using a web playground for Kotlin or an Xcode playground for Swift.

Declaring Properties

In both languages, there is a concept of mutability and immutability. Mutable properties can be changed or re-assigned but immutable properties can’t change.

Kotlin — Mutable Properties

Declaring an integer in Kotlin:

var age: Int = 15

To declare a property with type inference:

var firstName = "Ray"

Swift – Mutable Properties

Declaring an integer in Swift:

var age: Int = 15

To declare a property with type inference:

var firstName = "Ray"

63yuUrV.png!web

Kotlin — Immutable Properties

val hoursInADay = 24
val secondsInAMinute = 60
val quote = "If you don't work smart, you will probably be replaced by an AI."

Swift — Immutable Properties

let hoursInADay = 24
let secondsInAMinute = 60
let quote = "If you don't work smart, you will probably be replaced by an AI."

So, as you can see above, the basic difference between declaring immutable properties in Kotlin and Swift are the val and let keywords.

Data Structures

Data structures are an important part of any language. They are used to organize, store, and manipulate data. Arrays, linked lists, dictionaries or maps, classes and interfaces are all examples of data structures.

Arrays

In both Swift and Kotlin, arrays have a fixed type — i.e., an array could be a collection of strings, for example, but not a mixture of strings and integers.

Swift — Array

Declaring a mutable array in Swift:

var names = Array<String>()

To append values:

names.append("Fuad") //index 0
names.append("Eric") //index 1
names.append("Joe") // index 2

Declaring an immutable array in Swift:

let days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]

Kotlin — Arrays and Lists

In Kotlin, arrays can be mutable, but are declared with a fixed size. In the following example we declare a mutable array in Kotlin with five elements, all set to a default value of zero:

val numbers = Array<Int>(5){0}

To change the value of an item in the array:

numbers[1] = 2 //numbers is now (0, 2, 0, 0, 0)

Note that, while the array above is mutable , you were able to assign it to a immutable variable using the val keyword – more on this later.

Declaring an immutable array in Kotlin:

val days = arrayOf("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")

Another Kotlin collection type, lists are similar to Swift’s array type. Lists can have a variable number of elements and can grow in size after declaration.

var names = ArrayList<String>() //creates a list of strings, initially with no elements

To add values to a Kotlin list:

names.add("Fuad") //index 0
names.add("Eric") //index 1
names.add("Joe") // index 2

Declaring an immutable list in Kotlin:

val days = listOf("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")

Dictionaries / Maps

A dictionary (Swift) or map (Kotlin) is a very useful data structure when it comes to storing distinct values. While dictionaries and maps by default can expand, in both Kotlin and Swift, you can define their capacity for improved performance.

Kotlin

var namesWithAges = HashMap<String, Int>()
var namesWithAges = HashMap<String, Int>(20) //define capacity

Assigning values:

namesWithAges.put("John Doe", 34)
//OR
namesWithAges["John Doe"] = 34

Creating an immutable map:

val namesWithAges = mapOf("John Doe" to 34, "Jane Doe" to 29)

Swift

Creating a Swift dictionary:

var namesWithAges : [String: Int] = [:]
namesWithAges.reserveCapacity(20) //define capacity

Assigning values:

namesWithAges["John Doe"] = 34

Declaring an immutable dictionary:

let namesWithAges = ["John Doe" : 34, "Jane Doe" : 29]

Functions

Functions are the essential building blocks of any codebase. They help organize the code in a manner that makes it readable and maintainable.

Kotlin Functions

Prototype of a Kotlin function:

fun functionName(parameterName: DataType): ReturnType {
  //function body
}

The return type of a function is represented by a colon : . In Kotlin, all functions have a return type; if you don’t specify the return type, a special type Unit will be returned by default.

Here’s an example of a Kotlin function:

fun greetUser(name: String): String {
  return "Hello ${name}!"
}

Kotlin — Default Argument

In Kotlin, a default value can be assigned to a parameter. For instance, take the example of the above function.

fun greetUser(name: String = "World"): String {
  return "Hello ${name}!"
}

Now, the above function can be called without passing an argument like this:

greetUser() //returns Hello World!

Swift Functions

Prototype of a Swift function:

func functionName(parameterName: DataType) -> ReturnType {
  //function body
}

The return type of a function is represented by a -> . Additionally, the type of a function Swift infers when the function is not explicitly returning a value is a special type, Void , which is an empty tuple, written as () .

Writing an actual function in Swift:

func getGreetings(name: String) -> String {
  return "Hello \(name)!"
}

Swift — Default Argument

A Swift function with default argument:

func getGreetings(name: String = "World") -> String {
  return "Hello \(name)!"
}

Calling the function with its default behavior like:

getGreetings() //returns Hello World!

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? = nil
if (id != nil) {
  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 null")
}

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.

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".

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" }

Understanding Differences Between Swift and Kotlin

As you have seen, Swift and Kotlin are similar in many ways. However, they still have some differences.

Data Class vs. Struct

Swift has value types, such as structs, as well as reference types, while Kotlin only has reference types. Take a look at some examples.

Kotlin — Data Class

Consider the Person class from the previous examples in Kotlin:

val personOne = Person("Jon", "12 August")
val personTwo = personOne // assign to another variable 
personTwo.name = "Vanessa"
println(personOne.name) // prints Vanessa
println(personTwo.name) // prints Vanessa

Swift — Struct

Now, consider the above Person class as a Swift struct .

struct Person {
  let name: String
  let dob: String
}

let personOne = Person(name: "Jon", dob: "12 August")
var personTwo = personOne // assign to another variable
personTwo.name = "Vanessa"
print(personOne.name) // prints Jon
print(personTwo.name) // prints Vanessa

val vs. let

Other than not being able to re-assign the value, val and let do have a small difference in how they are handled across the two languages.

Kotlin — val

Consider the following persons list:

val persons = mutableListOf(Person("Jon", "12 August"),
  Person("Kim", "10 July"),
  Person("Vanessa", "12 August"),
  Person("Alisa", "26 March"))
persons.add(Person("Shaun", "11 Jan")) // can append a new value

Swift - let

In Swift:

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")]
persons.append(Person(name: "Shaun", dob: "11 Jan")) // throws compile time error

The fundamental difference here is in the treatment of an array or list. Kotlin lets you append values to a mutable list even when it's declared with a val . Similarly, you can declare an array in Kotlin using val and afterward re-assign members of the array using subscript notation. In contrast, in Swift, an array must be declared as mutable using var in order to have members updated with subscript notation or to append values to it.

Where to Go From Here?

After reading this comparison between Swift and Kotlin, you must have gotten a pretty good idea of how much they have in common.

Both of these languages are not limited to mobile development, either. They both are used for server side development and cross-platform app development as well. To serve this purpose there are a number of frameworks out there to help you with it. Vapor and Kitura are used for server side Swift and video courses on these can be found on our website. For Kotlin there is Spring Boot . For cross-platform app development there are frameworks like Kotlin-Native and Scade .

Finally, here are some additional resources to help you learn about the similarities and differences between Swift and Kotlin:

If you have any questions or comments, please let us know in the discussion below!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK