Kotlin For Beginners Guide

Download as pdf or txt
Download as pdf or txt
You are on page 1of 122

THE ULTIMATE

BEGINNERS’ GUIDE
CODING

Written by
Pooja Dutt
BECOME
A SOFTWARE
ENGINEER

For more software


engineering resources,
visit
www.coderatlas.com

As seen on
YouTube
@Pooja-Dutt
Intro to Kotlin (guide only)
Welcome to the Kotlin For Beginners Complete PDF Guide! In this guide, you’ll be
learning the basics of a new programming language - java’s best friend in fact! Kotlin is
both an object-oriented and functional programming language that uses the JVM (Java
Virtual Machine). It’s quickly becoming more popular than Java, C#, and many other
server-side languages due to its’ versatility and conciseness. If you want to learn more
about Kotlin as a language, feel free to check out this link [https://kotlinlang.org] It
provides all the needed information about why this language is so great!

Now, I know there are a lot of beginner programmer courses out there - but the unique
part about this one is that I've completely stripped this guide down to the most practical
things you need to know in order to land a software engineering role. This guide will
cover everything from variables, data types, operations, basic data structures, object
oriented programming, and more!

Intro to Kotlin (guide only) 1


As you read through the guide, I’d highly recommend that you practice
programming alongside me. That’s the only way you’ll actually end up retaining the
information. You can either use the online IDE (Kotlin) provided
[https://play.kotlinlang.org] - it’s just a matter of clicking on the link and getting started -
or you can take the time to actually set up your Integrated Development Environment
[https://www.jetbrains.com/idea/]!

At the end of each module, there will be practice problems and solutions that you can
use to test your knowledge! This is going to be a very interactive course, so please take
the time to actually do these problems, as it’ll give you a chance to learn how to code in
a deliberate way. These practice problems have been curated to build off previous and
current learnings so you can practice applying new knowledge to things that you
learned in previous modules. This will help give you a more holistic view of the Kotlin
programming language.

Alright, let’s get started! Don't forget to use the link provided above to open up your in-
browser IDE! Here it is again if you missed it: [https://play.kotlinlang.org]

Intro Script (guide only) 2


The first thing we’re going to try is printing some words to our console. The console is
where you can view the output of your code’s result once you compile and run the
program. There’s usually some special syntax you need to use to actually output this
code and view the result that you’re hoping for. We’ll be using ‘println’ to view our
intended result. Go ahead and delete everything except the first and last lines (ie. fun
main() {}). It should look like this:

fun main(){

We want to println() inside of our main function. This function is the entry point of the
program in Kotlin. It’s where we start executing the code that we’ve written. For the first
half of the course, all of the code that we’ll be writing will start in this main function().

Let’s go ahead and println() any sentence or word that you want to see. Usually this
sentence or word is called a string. And a string typically has quotation marks around
it.

Intro Script (guide only) 3


fun main(){
println("I’m so excited to learn about Kotlin!")
}

Now let's run it!

The code will automatically compile and run for you. See! We can see our message in
the console.

I'm so excited to learn about Kotlin!

Here's an example of how it looks in the online IDE. We'll be mostly using typed
examples styled in the PDF doc itself rather than taking screenshots from the IDE. It'll
be a bit easier to follow along that way. But for now, I want you to be able to view the
exact functionality in the IDE to make sure you are able to get started with the other
examples.

Intro Script (guide only) 4


[NOTE]
print() prints what you want the result to be on the same line
and println() prints a NEW line in the console

Now, programming languages are a bit fickle. You have to have exactly the right syntax
for this to work. If I, say, took out the parenthesis or quotation mark …

fun main(){
println("I’m so excited to learn about Kotlin!
}

I would get an error message like this in the console. It says we were expecting both the
'”' and the ')' → the closing parenthesis and closing quotation mark!

Intro Script (guide only) 5


Congratulations! You've written and run your first line of code! Let's cheers for more
coding to come

Oh btw, you're going to see some of the examples use something like this // before a
line sometimes. Those are called “comments”. They don't actually get compiled by the
code and they're just there so the author of the code can explain or clarify things to the
reader of the code.

For example:

fun main(){
// This is a comment!!!!!
println("I’m so excited to learn about Kotlin!
}

Ok, it’s your turn!


1) Try printing out your full name.
2) Try printing out five foods you love to eat on separate lines, and leave a comment
about why you love coding!

Intro Script (guide only) 6


Intro to Variables and Data Types
Now that you’ve learned how to print strings to the console, we’re going to learn about
variables and data types. Variables are just containers for storing certain values, and
data types are just a classification of data that tells the compiler how the programmer
intends to use the data. In Leyman’s terms, it’s a label.

Variables
Variables are denoted with the syntax val and var. We can use these keywords to tell
the program that we are about to create a variable and initialize it with a value. These
variables can be used over and over again throughout the code.

Data types
Data Types can be…
1) numbers → These are values that are made up of integers, floats, doubles, and
longs. Some examples are listed below.

Intro to Variables and Data Types 1


12938, 2938.0, 288888L, 12.0882938888F

2) strings → These are values that represent a word, sentence, or a letter. We used
strings in the first example when printing out a sentence to the console. Words (strings)
can be assigned to variables and are used quite frequently in programming languages.
Examples: “cat”, “c”, “The car jumped over the dog”

3) booleans→ These are values that represent a binary value (either true or false)

Intro to Variables and Data Types 2


Examples: true, false

4) characters→ These are values that are individual letters (or special characters).
They are similar to strings, but they comprise of only one letter at a time.
Examples: 'c', 'a', 't'

These are just a few examples of this next module - don't worry, we are going to cover
these variable keywords and data types in depth, coming up!

Intro to Variables and Data Types 3


What are variables - var vs val
Variables are just containers for storing data values. it’s kind of like having a label
for value.
For example, if you want to store the age of your dog in a variable, you’d probably just
store the number 5 in the variable “my_dog’s_age” rather than throw around the number
5 throughout the code. It makes your program a lot more readable this way.

Kotlin uses two different keywords to declare variables: val and var .

Use val for a variable whose value never changes. You can't reassign a value to a
variable that was declared using val . So you wouldn’t want to store your dog’s age
in this kind of variable, because that will age will increase over time.

Use var for a variable whose value can change. This type of variable would be
good for your dog's age (which changes), your bank account statement (which will
probably also change), as well as your weight.

In the example below, animal (the name of the variable) is a variable of type String
(data type) that is assigned an initial value of dog (the value):

var animal: String = "dog"

We learned about strings in the last lesson, but we can actually use variables to
represent even more kinds of data, which we will learn about shortly as well. Before we
move forward, let’s try to assign a value to a string and then print that value, using its’
variable name to the console (rather than just printing the value itself). This is a way to
reference a value in memory and re-use that variable in other parts of the code.

What are variables - var vs val 1


Remember to put these lines of code inside of the main function.

var animal: String = "dog"

println(animal)

Ok, let’s see what happens when we declare a val, and then try to re-assign it

val animal: String = "dog"

animal = "cat" // re-assigning to cat will result in an error (val)

println(animal)

If we try to compile the code, we receive an error.

Val cannot be reassigned

And, as you can see, once you use the keyword val or var once to define a variable,
you can just refer to it later as the name of the variable rather than adding “val” or “var”
to the beginning of your expression. Syntax rules that are easy to forget!

But we can try to re-assign a var

var animal: String = "dog"

animal = "cat" // re-assign animal = cat, instead of dog (var)


println(animal)

What are variables - var vs val 2


And it worked!

Now the Kotlin compiler can also infer the type of the variable without you explicitly
using “String” to tell the compiler that your variable is of type “String”. So, what does that
look like?

var animal = "dog"

println(animal)

Since the value of "dog" is of type String, the compiler infers that animal is also
a String
Note that Kotlin is a statically-typed language. This means that the type is resolved at
compile time and never changes.

What are variables - var vs val 3


How do we define numbers?
There are a lot of different ways to define numbers in Kotlin - namely, byte, short, float,
long, double, and int.
We’re mainly going to be focusing on Int and Double, but I’ll give a brief preview on all
the different types since they’re important to know.

Byte
The Byte data type can store whole numbers from -128 to 127. This can be used
instead of Int
or other integer types to save memory when you are certain that the value will be within
-128 and 127:

val myNum: Byte = 100


println(myNum)

If we try to create a byte with a value outside of it’s intended range…

val myNum: Byte = 500


println(myNum)

we’ll get an error like this:

The integer literal does not conform to the expected type Byte

How do we define numbers? 1


Short
The Short data type can store whole numbers from -32768 to 32767:

val myNum: Short = 5000


println(myNum)

If we try to use a value outside of the intended range like so…

val myNum: Short = 327677


println(myNum)

We get an error that looks like this

he integer literal does not conform to the expected type Short

Integer
The Int
data type can store whole numbers from -2147483648 to 2147483647:

val myNum: Int = 100000


println(myNum)

And this will result in an error:

val myNum: Int = -2147483648


println(myNum)

I think you get the gist for what the errors look like for this type of out of bounds range.
Go ahead and try coding these examples yourself!

How do we define numbers? 2


Long
The Long data type can store whole numbers from -9223372036854775807 to
9223372036854775807. This is used when Int
is not large enough to store the value. Optionally, you can end the value with an "L":

val myNum: Long = 15000000000L


println(myNum)

Floating point types represent numbers with a decimal, such as 9.99 or 3.14515.
The Float and Double data types can store fractional numbers:

Float

val myNum: Float = 5.75F


println(myNum)

Double

val myNum: Double = 19.99


println(myNum)

Use Float or Double ?


The precision of a floating point value indicates how many digits the value can have
after the decimal point. The precision of Float is only six or seven decimal digits,
while Double variables have a precision of about 15 digits. Therefore it is safer to
use Double for most calculations. Usually, you can use these numbers to represent
currency as well.
Also note that you should end the value of a Float type with an "F".

How do we define numbers? 3


Again, we will be using mostly Ints and Doubles for the remainder of these modules
because they are the easiest to work with.

How do we define numbers? 4


How do we define Strings and
Characters?
Strings
In Kotlin, a string is a collection of characters that can consist of a single letter, word, or
an entire sentence. It is represented by surrounding the value in double quotes and can
be assigned to a variable for printing or manipulation. Strings are used for storing text,
as we’ve discussed in the previous module. It can consist of a single letter, word, or an
entire sentence.
So again, we’re going to assign the string value to a variable called greeting and print
out the result to the console.

var greeting: String = "Hello World!"


println(greeting)

And as discussed before, because Kotlin can infer variables based on the value that
you assign it, we can also use this:

var greeting = "Hello World!"


println(greeting)

Let's look at some other examples of Strings

var greeting: String = "Hello World!"


println(greeting)

var oneLetter = "L"


var animal = "cat"

println(oneLetter)
println(animal)

How do we define Strings and Characters? 1


In these examples, you can see that Strings can consist of one word, a full sentence, or
even a single letter!

Characters
By now, you should be pretty familiar with strings. But did you know that they are made
up of these things called characters? A character is represented by a single letter
surrounded by single quotes. Characters are used to make up strings, which are
collections of characters. Each letter in a string is represented by an index, which can
be accessed to retrieve individual characters.

As mentioned above, a character is a just a single letter or symbol.

var letter : Char = 'y'


println(letter)

We can literally use single quotes to represent a Character.

Now, here’s where things get interesting. Because a string is just a bunch of Characters,
we can access each letter or special character in a string and set it equal to a character!

A string kind of looks like this:

[H, E, L, L, O, , W, O, R, L, D]
0. 1. 2. 3. 4. 5 6. 7. 8. 9 10

Each letter in the word, or string, is represented by an ‘index’. So you can actually
access each character in the string using the following method:

var word : String = "Hello World"


var getFirstLetter : Char = word[0]
println(getFirstLetter)

How do we define Strings and Characters? 2


All this means is that we are getting the first (or 0th letter in the String). We usually start
with the number 0 when counting up in Computer Science.
Let’s try this together. Create a string, and try to access the 4th element in the string.
Remember, because we are starting at the number 0, it might make things a little
trickier.

Example Solution:

var word : String = "Hello World"


var getFirstLetter : Char = word[3]

println(getFirstLetter)

How do we define Strings and Characters? 3


What is a Boolean?
Often times in computer science, we use a data type that represents yes or no, aka
true or false. This is called a Boolean. There are literally two values that you can use,
compared to thousands of different integer values, for example.

We can represent a Boolean like this:

var coldOutside : Boolean = true


var hotOutside: Boolean = false

println(coldOutside)
println(hotOutside)

Let's look at one more example

var iLikeTomatoes = false


var iHateTomatoes = true

println("Do I Like Tomatoes? " + iLikeTomatoes)


println("Do I Hate Tomatoes? " + iHateTomatoes)

There we go! Easy enough - there’s not much more to know about Booleans other than
the fact that the two values oppose each other. Also, just checking in with you all - these
examples are meant to be run by you too! Make sure you are running this code in your
own IDE to see how it works Play around with this to use different variable names as
well!

What is a Boolean? 1
Constants
In Kotlin, constants are variables that are assigned a value that cannot be changed.
They are defined with the const keyword and can be used throughout the program.
Once a constant is defined it is unchangeable (once you assign it a value). Constants
can also NOT be defined inside our main function, unlike the other data types we have
used so far.

We can define a constant in Kotlin like this:

const val result = 3

If we try to assign a new number to result

result = 2

we end up getting an error.

Val cannot be reassigned

Constants 1
Now remember, constants are defined outside of the main function. They'll end up
looking like this:

const val result = 3

fun main(){
println("This is the value of my constant: " + result)
}

They're referred to as global variables. We'll learn more about global variables later.
Let's take a look at another example before moving on!

const val NUMBER_OF_SCHOOL_DISTRICTS = 1583

fun main(){
println("We have " + NUMBER_OF_SCHOOL_DISTRICTS + " school districts in our state")
}

See, here, we usually use SNAKE_CASE to define a constant. There are other ways,
but this makes it more easy to see which values are constants without looking for the
const keyword.

Constants 2
Intro to Operators
There are different operators in Kotlin which represent a specific way to perform
operations on variables and values (or in other words, performing operations on
operands). I know - it’s a bit of a tongue twister

Arithmetic operators
Arithmetic operators in Kotlin allow for mathematical operations such as addition,
subtraction, multiplication, division, and remainder to be carried out on numerical data
types. These operators can be used with variables or constant values and return a new
value as a result of the operation.

Assignment operators
Assignment operators are used to assign values to variables. The most common
assignment operator is the equals sign (=), which assigns the value on the right-hand
side to the variable on the left-hand side.

Comparison operators
Comparison operators in Kotlin allow for comparison between two values or variables.
These operators return a boolean value of either true or false, depending on whether
the comparison is true or false. Examples of comparison operators include == for
equality, != for inequality, < for less than, > for greater than, <= for less than or equal
to, and >= for greater than or equal to.

Intro to Operators 1
Logical operators
Logical operators in Kotlin are used to combine multiple boolean expressions and
evaluate them as a single boolean expression. The three logical operators in Kotlin are
&& for logical AND, || for logical OR, and ! for logical NOT.

Intro to Operators 2
Arithmetic Operators
Arithmetic operators are used to perform common mathematical operations as shown in
the table below:

These are usually reserved for the numbers data types. As mentioned earlier, we’re
going to focus on using ints and doubles in these modules.
When you want to add ints together, you can do so like this. Again, remember to wrap
this inside of the main function.

var x : Int = 3 + 9 + 7

println(x)

// we've already declared x and y once so we don't need to use the 'var' or 'val' keywords
x = 4 + 5

println(x)

Arithmetic Operators 1
We’ve added two numbers and stored them inside the variable ‘x’. And the result is

19
9

You can also do the same thing with doubles:

var y : Double = 5.8 + 4.789 + 2.33

println(y)

y = 7.9 + 3.089 + 4.5

println(y)

But we can also store numbers separately in different variables and add them that way
as well.

var x : Int = 3
var y : Int = 8

println(x + y)

// we've already declared x and y once so we don't need to use the 'var' or 'val' keywords
x = 4
y = 8
println(x + y)

var f : Double = 2.6


var m : Double = 5.4

println(f + m)

f = 8.9
m = 1.78

println(f + m)

Arithmetic Operators 2
Now, one thing to note is that we can interchange doubles and ints and use operations
on them in the same function - but Kotlin will convert the int to a double. We'll also
remove the explict data type that we add in the definition this time. For example:

var x = 3
var y = 8.8

println(x + y)

// we'll end up getting an 11.8 because the int gets converted to a double

Let’s practice with some of the other Arithmetic operations as well. By the way, I've
started to remove the explicit data typing in many of these examples because a neat
trick will allow for Kotlin to, yet again, infer the data type so you don't have to worry
about it unless you want to override what Kotlin infers.
Subtraction:

var x = 3 // Int(s)
var y = 8

println(y - x)

var f = 3.99 // Double(s)


var m = 5.7

println(m - f)

var k = 3
m = 5.9

println(k - m)

Arithmetic Operators 3
Multiplication

var x = 3
var y = 8

println(y * x) // multiply 2 Integers

var f = 3.99
var m = 5.7

println(m * f) // multiply 2 Doubles


println(x * f) // multiply a Double and an Integer

Division

var x = 3
var y = 16

println(y / x) // Divide using 2 Integers

// note: when there is a remainder that occurs from dividing two ints, we round down.
// In this case, the result would be 5.

var f = 3.99
var m = 5.7

println(m / f) // Divide using 2 Doubles


println(y / f) // Divide using a Double and an Integer

By the way, remember to actually run these in your in-browser IDE! I'm not including all
of the outputs for that VERY reason. This is a check in to make sure you're getting the
most out of this guide

Modulus
A modulus is just a fancy way of saying a ‘remainder’. If you want to divide two numbers
and find out what the remainder is, then you can use the ‘%’ symbol.

Arithmetic Operators 4
Here's an example:

var x : Int = 3
var y : Int = 16

println(y % x)

The output would look like this:

The reason for this is 16/3 = 5(r1). We can divide 15 by 3, and then still have one left
over to make up the 16.

Increment and Decrement


The ++ will increase a value by 1, while the — will decrement a value by 1. Let's take a
look at an example!

var x : Int = 3
++x

println(x)

var y : Int = 9
--x

println(y)

There’s a lot of arithmetic operations to remember at first, but eventually you get used to
using these quite frequently as you continue on in in your programming journey. Let's do
a few practice problems to refresh our memories.

Arithmetic Operators 5
Bonus: we can actually use a few of these on other data types as well, namely, Strings.
For example, we can concatenate strings together using the + symbol.

var x = "Ban"
var y = "ana"

println(x + y)

This would give us an output of

Banana

We're just chunking the two words together to make one word. Easy, right?

Arithmetic Operators 6
Assignment Operators
Assignment operators are used to assign values to variables. We’ve already seen one
example of this in the previous modules.

var x = 8

In this example, we are setting the variable ‘x’ equal to a certain value. This is the most
basic example of an assignment operators.

However, we have some other examples of assignment operators as well - many times,
they’re used as a shortcut for some equations that we’ve already learned. In fact,
throughout this course, you’ll actually be taught about many of these shortcuts - this is
something that is unique to the Kotlin language. The language can be very concise and
easy to use for this very reason.

For example, we can turn

var x = 4
x = x + 7

println(x)
// here, we are setting x = 4. But then we are setting x = x + 7, which is x = 4 + 7

into this…

var x = 4
x+=7

println(x)

It’s very subtle, but we can use the addition assignment operator to increment x by
whatever number we want

Assignment Operators 1
Other examples include:

Let’s try a few more examples:

Subtraction

// notice how we've also stopped using var x : int = 3.


// Kotlin can infer the type based on the value that we've set x to,
// so we can be more concise in our assignments.

var x = 3
x-=2
println(x)

var y = 7.89
y-=4.5
println(y)

Assignment Operators 2
Multiplication

var x = 3
x*=2
println(x)

var y = 7.89
y*=4.5
println(y)

Division

var x = 3
x/=2
println(x)

var y = 7.89
y/=4.5
println(y)

Modulus

var x = 3
x%=2
println(x)

var y = 7.89
y%=4.5
println(y)

All we’re doing is using the equations we already know and making the code more
concise. Of course, you can always use operations on variables in the previously taught
examples - either way is valid, but over time, you’ll see that writing thousands of lines of
code may call for keeping individual lines as concise as possible.

Assignment Operators 3
Comparison Operators with
Numbers
Comparison Operators are used to compare two values. A Boolean is returned from these
comparison (either true or false). We can compare different data types such as numbers,
booleans, strings, and characters, which we’ll learn more about later as well.

Numbers
Equal To

Let’s start by comparing numbers first. We can check if two numbers are equal by using the ==
symbol.

var x = 9
var y = 4

var isEqual = x == y
println(isEqual)

// same as var isEqual : Boolean = (x == y) -> just an easier way to visualize what's being compared

Comparison Operators with Numbers 1


We are setting the variable ‘isEqual’ equal to the result of comparing x and y. In this case,
because x is NOT equal to y, ‘isEqual’ will equal ‘false’.

Here’s an example where ‘isEqual’ would be ‘true’.

var x = 9
var y = 9

var isEqual = x == y
println(isEqual)

Not Equal

We can also check if a number is NOT equal to another number using != (≠). For example,

var x = 9
var y = 4

var notEqual = x != y
println(notEqual)

This would make the variable ‘notEqual’, true, because ‘x’ is NOT equal to ‘y’. Likewise, if ‘x’ IS
equal to ‘y’, ‘notEqual’ would be false.

var x = 9
var y = 9

var notEqual = x != y
println(notEqual)

Greater Than or Less Than

We can also check if a number is greater or less than another number

Comparison Operators with Numbers 2


// greater than
var x = 9
var y = 8

var isGreaterThan = x > y


println(isGreaterThan)

// less than (remember, because we already defined 'x' and 'y', we don't
// need to use the 'var' keyword)
x = 9
y = 8

var isLessThan = x < y


println(isLessThan)

Greater Than OR Equal to (Less Than OR Equal to)

We can also check if a number is greater than or equal to another number, OR less than or
equal to another number using the following symbols

// greater than
var x = 9
var y = 8

var isGreaterThanOrEqualTo = x >= y


println(isGreaterThanOrEqualTo)

// less than (remember, because we already defined 'x' and 'y', we don't
// need to use the 'var' keyword)
x = 9
y = 8

var isLessThanOrEqualTo = x <= y


println(isLessThanOrEqualTo)

// equal to
x = 9
y = 8

isGreaterThanOrEqualTo = x >= y
println(isGreaterThanOrEqualTo)

// equal to
x = 9
y = 9

isLessThanOrEqualTo = x <= y
println(isLessThanOrEqualTo)

Comparison Operators with Numbers 3


Comparison Operators with
Strings and Characters
We can also use some of these comparison operators on other data types, as mentioned
before. For example, we can actually compare strings and characters as well. This may
get a bit complicated as we start to learn about structural equality vs referential equality,
but let’s start with comparing equality of value (or structure).

1) Strings
Equal To

For example, let’s check the equality between two strings using ==. In this case, the two
strings are of equal value, to ‘isEqual’ would be true. However, if we were checking the
equality of two strings that had different values.

var x = "Let's Learn to Code!"


var y = "Let's Learn to Code!"

var isEqual = x == y
println(isEqual)

However in this case,

var x = "Let's Learn to Code!"


var y = "Let's Learn to Code, Everyone!"

var isEqual = x == y
println(isEqual)

‘x’ and ‘y’ would not be equal. Even though there are some words in this string that are
considered equal, ie. ‘Let’s Learn to Code…’, it doesn't match exactly.

We an also use the != (≠) symbol to compare strings as well.

Comparison Operators with Strings and Characters 1


var x = "Let's Learn to Code!"
var y = "Let's Learn to Code!"

var isNotEqual = x != y
println(isNotEqual)

x = "Let's Learn to Code!"


y = "Let's Learn to Code, Everyone!"

isNotEqual = x != y
println(isNotEqual)

The first comparison would return ‘false’ since ‘x’ is equal to ‘y’ (but we are comparing
the two values to see if they are NOT true), and the second comparison would return
‘true’ since the two values are NOT equal to each other.

Another way to compare two strings is using the .equals() method that is part of the
String class. We’ll learn more about classes later, but the String class in particular has
pre-written functions attached to it, and the equals() keyword is one of those functions.

Here’s a quick example. But for now, we can stick to using ==.

var x = "Let's Learn to Code!"


var y = "Let's Learn to Code!"

var isNotEqual = x.equals(y)


println(isNotEqual)

Comparison Operators with Strings and Characters 2


2) Characters
We can do the same thing with characters as well!

For example,

var x = 'G'
var y = 'G'

var isEqual = x == y
println(isEqual)

var isNotEqual = x != y
println(isNotEqual)

x = 'G'
y = 'H'

isEqual = x == y
println(isEqual)

isNotEqual = x != y
println(isNotEqual)

3) Referential Equality
There's this thing called referential equality in Kotlin. Referential equality is a way of
checking whether two variables are referencing the same object in memory. In Kotlin, we
use the === operator to check for referential equality. However, Kotlin's compiler
optimizes by finding cached values that already exist with the same value, and uses
them as a way to “mock” referential equality between variables. This can sometimes lead
to unexpected results when checking for referential equality.

Now, we’ve checked the equality of two values with both strings and characters, but what
about checking the equality of two values based on reference? Well, let me explain what
that means first. When you declare a variable like

var a = "hello"

You are allocating memory for this particular string. The variable ‘a’ is pointing to the
value “hello” on the stack. Now, we can also have other variables point to the same value

Comparison Operators with Strings and Characters 3


on the stack as well by setting another variable equal to ‘a’.

For example

var a = "hello"
var b = a

In this case, both ‘a’ and ‘b’ are equal to “hello” (structural equality), but they ALSO point
to the same value In memory (as shown in the image above). So, they also have
referential equality. The way that we check referential equality is using ===.

var a = "hello"
var b = a
var c = "hello"

println(a == b) // true
println(a === b) // true

println(a == c) // true
println(a === c) // true - only because of the way kotlin caches these values at compile-time

4) compareTo() function
We can also compare two strings using the .compareTo() function, which is another
function that is part of the String class. Instead of returning a Boolean (true or false
value), it will return a number. But what does the number mean? Well, if it returns a 0,
that means the strings are equal. If it returns a negative number, that means the string to
the left of the expression is less than the string to the right. If it returns a positive
number, that means the string to the left of the expression is greater than the string to
the right. Now, what does it mean to have a string that is less than or greater than
another string?

Comparison Operators with Strings and Characters 4


Strings have a hierarchy based on alphabetical order, and based on its’ capitalization.
Typically, strings are compared by each of its’ first letters - whichever comes first
alphabetically is considered the less than string. If the first two letters are the same,
then it compares the next two letters until it gets to the end of each string. Likewise, if
one string is lowercase and the other is capitalized, then the capitalized string is
considered less than the lowercase string. These values are actually all based on the
values in the ASCII table. You can verify by comparing the value of each character in this
table and adding up the results.

Lastly, we also give priority to strings that are longer. For example, if we have two strings

var a = "examination"
var b = "exam"

By the logic mentioned above, they are both the same, until we start comparing the
values after “exam”. Because variable ‘b’ has no letters afterwards, it is considered less
than variable ‘a’, which does have more letters after the word ‘exam’.

I know, it can be a bit confusing, but let’s try a few examples to get used to the
compareTo() method. Remember, this is just another way of comparing two strings. You
can still use the greater than symbol (>) or less than symbol (<) to compare two strings.

var a = "examination"
var b = "exam"
var c = "exam"
var d = a
var e = "Examination"
var f = "fish"

println(a.compareTo(b))
println(a.compareTo(c))
println(a.compareTo(d))
println(b.compareTo(e))
println(e.compareTo(f))
println(b.compareTo(f))

Comparison Operators with Strings and Characters 5


Logical Operators
Logical operators are used to determine the logic between values. We use them to
compare several expressions with each other to make sure they are all true, or all false
- or maybe there’s a criteria that one of those expressions have to be true.

Regardless, it gives us a way to logically make decisions in our programs. For example,
what if we wanted to determine whether or not school will be open today. Some factors
we could use are “Are there any snowstorms coming today?” or “is it a national holiday
today?” we will have to compare both of these expressions. If one or the other is true,
then we don’t go to school that day.

Here’s a table to showcase the logical operators that exist in Kotlin:

We can use truth tables to understand how these logical operators work

&& (AND)
In this case, we can see that when both ‘x’ and ‘y’ are true, then the expression results
in true. If they are both false, the expression also false. But if one is false, and the other
is true (and vice versa) then the expression results in false. Basically, both expressions
need to result in the same value for the expression to result in true.

Logical Operators 1
We use && to represent if both expressions have the same result and they have to be
true. For example, if we play a game where the only way to win is to flip two coins and
get either both heads, or both tails, then we can represent this game using the following
expression

var coin1 = true // true represents 'heads', false represents 'tails'


var coin2 = true

println(coin1 && coin2)

coin1 = true
coin2 = false

println(coin1 && coin2)

|| (OR)
In this case, we can see that when either ‘x’ and ‘y’ are true, OR both ‘x’ and ‘y’ are true,
then the expression results in true. If they are both false, the expression results in false.
Basically, at least one variable has to be true for the entire result to be true.

Logical Operators 2
Let’s try an example with determining if school will be open today (as mentioned
previously)

var isSnowStorm = true


var isNationalHoliday = false

var isSchoolClosed = isSnowStorm || isNationalHoliday


println(isSchoolClosed) // true

isSnowStorm = false
isNationalHoliday = false

isSchoolClosed = isSnowStorm || isNationalHoliday


println(isSchoolClosed) // false

! (NOT)
Lastly, we can check if something is NOT itself by using !. All this means is that we are
checking the opposite of its’ value.

For example

var isSchoolOpen = true


var teenagersAreHappy = !isSchoolOpen

println(teenagersAreHappy)

Logical Operators 3
We can obviously just start out with a variable that equals false, but in ‘human language’
it makes more sense to use ! to describe whether or not the teenagers are happy if
school is NOT open. We may also use the isSchoolOpen variable for other reasons
such as

var isSchoolOpen = true


var teachersComeToSchool = isSchoolOpen
var teenagersAreHappy = !isSchoolOpen

println(teachersComeToSchool)
println(teenagersAreHappy)

We can also take these expressions further by comparing several expressions at once.
Using the (), we can actually execute expressions in the parentheses first and then
move forward with executing the other expressions (just like in a normal mathematical
expression)

var isPayDay = true


var isSnowStorm = true
var isNationalHoliday = false
var hasHomework = false

var teachersAreHappy = isPayDay && !(isSnowStorm || isNationalHoliday)


println(teachersAreHappy)

var teenagersAreHappy = (isSnowStorm || isNationalHoliday) && !hasHomework


println(teenagersAreHappy)

We can also use these to compare number expressions as well. For example

var x = 9
var y = 12
var z = 8.6

var isTrue = (x <= y) && ((z > x) || (x > z))


println(isTrue)

Logical Operators 4
Intro to Statements and Loops
Conditional Statements
Conditional Statements are used to create actions for different decisions that are made
using logical operators. I know that’s a mouthful, but it’s basically like using a decision
tree.

You can have certain checks in your code to make a decision and move forward with
one section of code, rather than a different section of the code, as shown above. “Being
Hungry” will result in a true or false, and depending on that answer, you can either go
left or right. If you’re hungry, you check to see if you can spare some money. If you’re
not, then you go to sleep.

Conditional statements include if, if else, and when statements.

Intro to Statements and Loops 1


Loops
Loops are a way for you to run through a snippet of code multiple times. In
programming, it’s important to keep your code concise and not repeat the same exact
syntax over and over again - it makes the code more readable and manageable overall.

For example, if you want to print the numbers 1 through 5, we can do so like this

println(1)
println(2)
println(3)
println(4)
println(5)

Or, we can do it like this:

for(i in 1..5){
println(i)
}

It’s a more concise way to show the same exact thing.

In Kotlin, there are a few different loops we can use - for loops, while loops, and nested
loops.

Intro to Statements and Loops 2


Conditional Statements
As mentioned earlier, you can use conditional statements to perform different actions for
different decisions that are made.
Kotlin has the following conditionals:

Use if to specify a block of code to be executed, if a specified condition is true

Use else to specify a block of code to be executed, if the same condition is false

Use else if to specify a new condition to test, if the first condition is false

Use if..else to set a variable equal to the result

So what does all of this mean exactly? Well, let's look at a similar flow diagram from the
introduction.

We start at the ‘start’-ing point, and then evaluate case1 first. Based on the result of
case1, either we move to outcome1 (if the result is true), or we move to evaluating

Conditional Statements 1
case2 (if the outcome is false). The different cases we evaluate are usually one of the
expressions we’ve learned to create in the Operators section.

The code for this diagram would look like this:

if(case1){ // evaluate step 1


println(outcome1) // if step1 = true
} else if(case2){ // evaluate step 2 (if step 1 = false)
println(outcome2) // if step2 = true
} else {
println(outcome3) // if step2 = false
}

Confused yet? Well, let’s look at some examples.

If Statement
Let’s start with an if statement. An if statement will help us evaluate one expression, or
one case.

if (condition) {
// block of code to be executed if the condition is true
}

A concrete example of this would look like. Remember to write all of this functionality
within the main function()

if(7 < 13){


println("this expression is true!")
}

We evaluate whatever is in the parenthesis of the if statement, and then println("this


expression is true!") if the statement is true.

Conditional Statements 2
In this case, what would we print if x = 8?

var x = 8

if(x < 13){


println("x is less than 13")
}

println("done!")

The answer is

x is less than 13
done!

the first expression x < 13 is true, so we println(”x is less than 13”). After printing x,
we’re not done yet. We continue executing the rest of the code, so we println(x) again
a second time.
Note: Now, if we are using the return keyword, we usually stop executing any code
after hitting this, but we’ll talk more about this later when we get to functions.

What if x was equal to 16? Well, let’s test that scenario out.

var x = 16

if(x < 13){ // this is false


println("x is less than 13")
}

println("done!")

the if statement would evaluate to false here, so we would skip that chunk of code
altogether and move onto the last print statement. We’d never set x = 15 either and

Conditional Statements 3
would get a result of 16.

done!

Else Statement
If we want to exclusively execute some code based on if the expression is false, we can
use something called an else statement

var x = 16

if(x < 13){ // this is false


println("x is less than 13")
} else {
println("x is greater than 13")
}

In this case, since x is greater than 16, we skip the execution of the first expression and
print println("x is greater than 13") within the else statement.

x is greater than 13

Conditional Statements 4
Else If Statement
The last example uses an else if statement. Basically, this allows us to evaluate
multiple expression (kind of like the diagram that was shown earlier).

if(case1){ // evaluate step 1


println(outcome1) // if step1 = true
} else if(case2){ // evaluate step 2 (if step 1 = false)
println(outcome2) // if step2 = true
} else {
println(outcome3) // if step2 = false
}

We can incorporate an else if statement into the following code:

var x = 17

if(x < 15){ // evaluate step 1


println("x is less than 15") // if step1 = true
} else if(x > 23){ // evaluate step 2 (if step 1 = false)
println("x is greater than 23") // if step2 = true
} else {
println("x is between 15 and 23") // if step2 = false
}

println("done!")

Just like the previous examples, we check the first if statement, proceed to the else if,
and then finally finish at the else statement.

The result would look like

x is between 15 and 23
done!

Conditional Statements 5
if Else Statement
In Kotlin, you can also use if..else statements as expressions (assign a value to a
variable and return it)

val clock = 20

val greeting = if (clock < 12) {


"Good day."
} else if (clock < 18) {
"Good afternoon."
} else {
"Good evening."
}
println(greeting)

We’ve set the result equal to greeting (assigning the result of the if…else statement to
this variable) and then print greeting to the console. The result looks like:

Good evening.

Conditional Statements 6
When statement
A when statement is very similar to if statements, but they’re useful to use when there’s
usually a very specific set of requirements that need to be evaluated, or just a lot of
different expressions that need to be evaluated at the same time.

Use when to specify many alternative blocks of code to be executed

For example, based on what the result of day is, we can go through several cases and
then println(”Friday”) based on the 5th case. Notice that we pass in ‘day’ as a parameter
to the when statement (we’ll learn more about parameters later, but it’s kind of like an
input to a function)

val day = 5

when (day) { // day = input


1 -> println("Monday") // if day = 1, print Monday
2 -> println("Tuesday") // if day = 2, print Tuesday
3 -> println("Wednesday") // ..
4 -> println("Thursday") // ..
5 -> println("Friday") // ..
6 -> println("Saturday") // ..
7 -> println("Sunday") // ..
else -> println("Invalid day.") // anything else, print Invalid day
}

When statement 1
Just like the if..else statement, you can also set a variable equal to the result of the
when statement and then print the result at the end. The biggest difference here is
assigning the result to a variable, versus just printing out the result right away in the
console.

val day = 5

val result = when (day) { // set val result = to whatever the result is!
1 -> "Monday"
2 -> "Tuesday"
3 -> "Wednesday"
4 -> "Thursday"
5 -> "Friday"
6 -> "Saturday"
7 -> "Sunday"
else -> "Invalid day."
}
println(result)

In this previous example, you can start to see how using conditional statements can
result in a value that is used elsewhere in the code. At the end of the day, all we’re
doing is computing answers to equations and using the result throughout the rest of the
code.

When statement 2
For Loop

A for loop is a way to iterate through a collection of elements, such as a range of


numbers or a list of items. In Kotlin, you can use the "for" keyword followed by the
variable name and the range of values to loop through, and execute code for each
iteration of the loop. Let’s start with counting through a range of numbers 1-5. Here,
what we'll do is create a variable num in the for loop, and num will represent the
numbers 1 through 5 (one at a time).

for(num in 1..5){
println(num)
}

First, num = 1, and then enters inside the loop and executes whatever code is in there.

Then, num = 2, and then enters inside the loop again to execute the code

Eventually, this is the result we get

1 // num = 1, println(1)
2 // num = 2, println(2)
3 // num = 3, println(3)
4 // num = 4, println(4)
5 // num = 5, println(5)

For Loop 1
We can also use different data types within for loops. For example,

for(chars in 'a'..'e'){
println(chars)
}

This will print all the characters between ‘a’ and ‘e’. The result will look like this:

a // chars = 'a', println('a')


b // chars = 'b', println('b')
c // chars = 'c', println('c')
d // chars = 'd', println('d')
e // chars = 'e', println('e')

Looping is a great way to quickly go through a collection of elements without having to


write code over and over again. It's a good way to recycle code that you feel might be
repetitive.

For Loop 2
While and Do While Loop
While loops can execute a block of code as long as a specified condition is reached.
We can define this condition outside of the loop itself, and then modify the condition
within the loop.

Do while loops are similar to while loops but they will execute the code block once,
before checking if the condition is true, then it will repeat the loop as long as the
condition is true.

While Loop
What do I mean by this? Well, let’s look at an example

var doSomething = true

while(doSomething){
// execute code
}

The way that we’ve written this is the same as saying. The == true is implied.

var doSomething = true

while(doSomething == true){
// execute code
}

Now, if the condition doSomething is never false, we could run out of memory by just
staying in the loop forever. We need to specify a condition where doSomething
eventually equals ‘false’ in order to exit the loop.

While and Do While Loop 1


Like this

var doSomething = true


var time = 0

while(doSomething){ // while doSomething == true


time += 2 // increment time by 2

if (time >= 12) {


doSomething = false // if time >= 12, than we set doSomething = false
}

println(time) // print current time


}

doSomething starts out as true, but then we increment time by 2, and then check if
time is greater than or equal to 12. If it is, then we set doSomething = false, and
continue on with the code until the loop starts again. At that point, we’d exit the loop
because the statement of doSomething no longer holds true.

The result would look like this

2
4
6
8
10
12

Now, what If we wanted to exit the loop immediately after we found out doSomething =
false? Instead of executing the rest of the code in the while loop and then evaluating
doSomething’s value once we start the loop again, we can actually stop executing the
loop in the code altogether.

While and Do While Loop 2


var doSomething = true
var time = 0

while(doSomething){ // while doSomething == true


time += 2 // increment time by 2

if (time >= 12) {


break // exit loop right away
}

println(time) // print current time


}

The result of this would not include 12, because we exit the loop before even getting to
println(12)

2
4
6
8
10

Do While Loop
Do while loops are similar to while loops but they will execute the code block once,
before checking if the condition is true, then it will repeat the loop as long as the
condition is true.

This is what the structure of a Do while loop look like

do {
// code block to be executed
while (condition);

While and Do While Loop 3


Here’s a real example that we can use

var num = 0
do {
println(num)
num++
}
while (num < 5)

The result of this would be

0
1
2
3
4

While and Do While Loop 4


Nested Loops
Now that we've learned what a loop is, we can take it a step further and execute one
loop inside another loop (and even two, or three, loops inside of another loop - but that
may be expensive in terms of computing power)

So, how does that work exactly?

Well, the first loop helps us go through a range of items

[1,2,3,4,5]

for(i in 1..5){
println(i)
}

The second loop (nested loop) matches every element in the second range with every
element in the first range. I know that’s a bit confusing, but let’s take a look at some
examples.

for(i in 1..5){
for(j in 2..6){
println(i + j)
}
}

First, we’d start with i = 1, and then jump into the second loop, where j = 2. But then we
continue executing everything in the second loop while i = 1, because we’re not done
with that loop yet. It’s kind of like inception.

Nested Loops 1
So, it would look like this

i = 1, j = 2, println(3)
i = 1, j = 3, println(4) // increment j
i = 1, j = 4, println(5) // increment j
i = 1, j = 5, println(6) // increment j
i = 1, j = 6, println(7) // increment j
// now we've gotten to the end of the second loop, so we go back up to the first loop
// and we increment i to 1
i = 2, j = 2, println(4)
i = 2, j = 3, println(5) // increment j
i = 2, j = 4, println(6) // increment j
i = 2, j = 5, println(7) // increment j
i = 2, j = 6, println(8) // increment j
// now we've gotten to the end of the second loop, so we go back up to the first loop
// and we increment i to 3
i = 3, j = 2, println(5)
i = 3, j = 3, println(6) // increment j
i = 3, j = 4, println(7) // increment j
i = 3, j = 5, println(8) // increment j
i = 3, j = 6, println(9) // increment j
// now we've gotten to the end of the second loop, so we go back up to the first loop
// and we increment i to 4
i = 4, j = 2, println(6)
i = 4, j = 3, println(7) // increment j
i = 4, j = 4, println(8) // increment j
i = 4, j = 5, println(9) // increment j
i = 4, j = 6, println(10) // increment j
// now we've gotten to the end of the second loop, so we go back up to the first loop
// and we increment i to 5
i = 5, j = 2, println(7)
i = 5, j = 3, println(8) // increment j
i = 5, j = 4, println(9) // increment j
i = 5, j = 5, println(10) // increment j
i = 5, j = 6, println(11) // increment j
// now we're done!

Nested Loops 2
The overall result would look like this

3 // first iteration, i=1


4
5
6
7
4 // second iteration, i=2
5
6
7
8
5 // third iteration, i=3
6
7
8
9
6 // fourth iteration, i=4
7
8
9
10
7 // fifth iteration, i=5
8
9
10
11

Similar to a regular for loop, you’re just executing code inside the loop before
incrementing to the next number in the range. So we’ll execute println() 5 times.

for(i in 1..5){
println(i) // here we're just printing something
}

But when there’s a loop inside another loop, then we are executing the loop 5 times.
The number of computations is M x N (or the first loops’ range x the second loop’s
range). In the previous example, we made 25 computations because the range was 5
for the first loop, and 5 for the second loop.

Nested Loops 3
Functions
What is a Function?
Functions actually aren’t too new - we’ve been using functions such as println() and the main function this entire
time. But we still need to learn the basic structure of a function functions, which can take no input and have no
output, or also take an input and/or compute an output are a pretty important part of any programming language.

Some functions don’t even take an input (or have an output). Functions with no output are called void functions.
Here’s an example of a really basic function that doesn’t take an input, and doesn’t have an output. (println()
doesn’t count as a result that gets returned).

fun myFunction() {
println("I just ran a function!")
}

You can call this function in your main function() as well. You’ve already defined it above, (NOTE: You always
define the function outside of your main function. but you're not actually using it anywhere until you call it. A
function is the like the definition of an equation - but calling it elsewhere allows you to actually execute the code.

fun main(){
myFunction()
}

Altogether, it would look like this:

fun main(){ // main function is here


myFunction() // call new function
}

fun myFunction() { // create new function (outside of main function)


println("I just ran a function!")
}

The result looks like

I just ran a function!

The benefit to using functions is that we can create a function once and then use it several times in other parts of
the code. It reduces the need to repeat instructions or computations.

Functions 1
Here’s an example of us calling the same function multiple times

fun main(){
myFunction()
myFunction()
myFunction()
}

Which will output

I just ran a function!


I just ran a function!
I just ran a function!

Functions are very similar to a math equation. We can also add input and output values in the equation, where f
is the name of the function, x is the input value, and 3x + 1 is the logic that is computed with the input value to
result in an output value. We’ll talk more about input and output values in a second.

Input Parameter
Let’s try an example of a function with an input variable. we pass in an input variable into the function
parameters, and also specify the type (ie. Int, Double, String, etc)

fun functionName(inputName: inputType) {


// do some computation with the input
println(result)
}

With the proper syntax, it looks like this

Functions 2
fun getSalary(currentSalary: Double) {
var newSalary = currentSalary + 10000
println(newSalary)
}

We can also call this function in our main function (with different inputs)

fun main(){

var currentSalary1 = 125000.00


getSalary(currentSalary1)

var currentSalary2 = 80000.00


getSalary(currentSalary2)

The result would look like

135000.00
90000.00

Return Value
Now, let’s try with both an input (parameter) AND an output. Remember, an output has to be one of the data
types we’ve specified before. There are example of other types of outputs, but we’ll cover that later.

fun functionName(inputName: inputType) : outputType {


// do some computation with the input
return result // output value (return is used to exit the function and give the output result - kind of like 'break')
}

Or, in proper coding terms

fun getSalary(currentSalary: Double) : Double {


var salary = currentSalary + 10000
return salary // output value (return is used to exit the function and give the output result - kind of like 'break')
}

getSalary is the name of the function, the currentSalary is the name of the input variable (like in the previous
example), and Double is used to specify the type of output value. We use the keyword return to signify the end

Functions 3
of the function and to return the value at that time. This function can be re-used in the code over and over again
like this

fun main(){

var currentSalary1 = 125000.00


var newSalary1 = getSalary(currentSalary1)

var currentSalary2 = 80000.00


var newSalary2 = getSalary(currentSalary2)

println(newSalary1)
println(newSalary2)

As you can see in the example above, we call getSalary() twice and pass in two different input variables
(currentSalary1 and currentSalary2) and set the result equal to two different output variables (newSalary1 and
newSalary2). That’s a lot easier than typing out the contents of the function twice.

The result is

135000.00
90000.00

Multiple Parameters
Let’s try some more examples! We can also have more than one input param

fun getSalary(currentSalary: Double, yearsOfExperience: Int) : Double {


var salary = currentSalary + 10000
salary += (yearsOfExperience * 1500)
return salary // output value (return is used to exit the function and give the output result - kind of like 'break')
}

We can call this function (twice) in our main function

fun main(){

var currentSalary1 = 125000.00


var newSalary1 = getSalary(currentSalary1, 4)

var currentSalary2 = 80000.00


var newSalary2 = getSalary(currentSalary2, 10)

println(newSalary1)
println(newSalary2)
}

Functions 4
And this is what the result will look like

141000.0
105000.0

Don't forget to code along in your IDE - it's really important to understand what a function is, how to add input
parameters, and have a return type - as well as calling the function in the main function.

Functions 5
Intro to Data Structures

Data structures are a pretty important and fundamental concept in computer science.
They’re used to store and organize data in an efficient way.

Here are some data structures that we’ll be learning about:

Arrays
Arrays are a basic data structure that store a collection of elements of the same type.
This can range from primitive to non-primitive data types such as integers, boolean,
longs, and even other arrays and array lists. They offer constant-time access to
individual elements, but have a fixed size and are not easily resizable. In Kotlin, arrays
can be created using the arrayOf() function.

ArrayLists
Array lists are similar to arrays, but offer dynamic resizing and are implemented using
an underlying array. They can grow or shrink as needed, but accessing elements is
slower than with arrays due to the need to perform bounds checking. In Kotlin, array
lists can be created using the mutableListOf() function.

Intro to Data Structures 1


HashMaps
Hash maps are a data structure that use a hash function to map keys to values. This
allows for constant-time access to values given a key, making them useful for large
datasets. However, hash maps do not preserve the order of elements and collisions can
occur if multiple keys hash to the same value. In Kotlin, hash maps can be created
using the mutableMapOf() function.

These data structures may seem similar at first, but they also have vital differences that
will help you decide when it’s appropriate to use each one.

Intro to Data Structures 2


Arrays
Ok so let’s start with arrays as our first data structure. An array is a non-resizable
structure that is used to store all different kinds of data, including integers, floats,
booleans, strings .. and even non-primitive types such as other arrays.

Introduction
The best way to think of an array is like a row on an excel file. Visually, it looks like a
large (and long) container that is broken up into smaller containers like so:

Each container has an index, starting from 0 until the length of the array-1. In this
example, we can see that the array has Integers inside of it. In kotlin, you have to
initialize the array to store ONE type of data. You can’t mix and match data types inside
of an array like you can in a language such as javascript.

Let’s look at a coding example. We are going to delcare an empty array of size 4.
Remember, arrays are NON-resizable, so we have to declare the size of the array as
soon as we initialize it.

var numbers = IntArray(4)

Arrays 1
This is the same as

As you can see, there are no values in the array, but it has a length of 4. Likewise, we
can also initialize an array with values inside of it like so:

var numbers = arrayOf(40, 55, 63, 17, 22, 68, 89, 97, 89)

In this example, we’ve initialized an array with numbers already populated inside of it.
Kotlin will assume the array is of size = 9 since we’ve added 9 numbers into the array
(this is a specific case where we don’t have to specify the size).
This will look something like this:

We have the array populated with values, and we also have the indexes below to
represent where they are in the array.

Arrays 2
Accessing and removing values from an array
So, how about accessing and removing elements after we’ve initialized our array? and
what can we use arrays for in real life?

Well, let’s say we are a car dealership. We have the following cars in our inventory so
far.

var cars = arrayOf("Volvo", "Toyota", "Porsche", "BMW", "Tesla Model Y")

We’ve already initialized our array with some values, and we only have room to hold 5
cars at a time. But let’s say a customer comes into the dealership and decides to buy
the Porsche. Well, first we’d have to access the car in the array and remove it from our
inventory.
We can access elements in array by referring to their index like so:

var cars = arrayOf("Volvo", "Toyota", "Porsche", "BMW", "Tesla Model Y")


// 0 1. 2. 3. 4

var car: String = cars[2] // car should equal "Porsche"


println(car)

And then we can set that index’s value to an empty string to represent removing the
Porsche from inventory:

cars[2] = ""

Now our list looks like this with the Porsche removed. The array is still the same size,
but we've just made one of the “parking” spaces empty.

var cars = arrayOf("Volvo", "Toyota", "", "BMW", "Tesla Model Y")


// 0 1. 2. 3. 4

Arrays 3
But what if we don’t even know If we have a Porsche in our inventory, let alone which
index it exists at? Well, we can use the “in” keyword to find out if that element even
exists in our array.

var cars = arrayOf("Volvo", "Toyota", "Porsche", "BMW", "Tesla Model Y")


// 0 1. 2. 3. 4

if ("Porsche" in cars) {
println("It exists!")
} else {
println("It does not exist.")
}

Ok, so we know how to find out whether a certain element exists in our array, but what if
we want to find the EXACT spot where the Porsche is in our array? Maybe each index
represents a parking spot in our dealership’s garage? Well, we could use a for loop
(remember, we learned about those a while back) to step through each element in the
array and return the index that we find the item at.

var cars = arrayOf("Volvo", "Toyota", "Porsche", "BMW", "Tesla Model Y")


// 0 1. 2. 3. 4

for(i in cars.indices){ // accessing the array's indices


if(cars[i] == "Porsche") println("Car exists in Parking Spot " + i)
}

The above example is using I to represent the current index we are at. We step forward
through the array one element at a time, and once we find the car we are looking for, we
can print out the parking spot it is in.

output will look like this:

Car exists in Parking Spot 2

Arrays 4
And we can remove that element just like how we learned in the first example.

// i = 2

cars[2] = ""

Adding/overriding values to an array


So what if we get a new car shipped in the same day the Porsche was bought by a
customer? Remember, we have a limited number of spots in the garage, but we can
actually add a new car into the same parking spot as where the Porsche used to be.

Currently, our array looks like this:

["Volvo", "Toyota", null, "BMW", "Tesla Model Y"]


//. 0. 1. 2. 3. 4

Let’s add the new car, a Ford, where the Porsche used to be.

cars[2] = "Ford"

Now, our array looks like this:

["Volvo", "Toyota", "Ford", "BMW", "Tesla Model Y"]


//. 0. 1. 2. 3. 4

We can also override any existing values in the array, so we need to make sure the
element is empty before we start adding things. For example, let’s say we get a Range

Arrays 5
Rover shipped to us today and we try to store in the last index.

cars[4] = "Range Rover"

Now our array looks like this:

["Volvo", "Toyota", "Ford", "BMW", "Range Rover"]


//. 0. 1. 2. 3. 4

We’ve effectively override the Tesla Model X with a Range Rover. So, be very careful
about checking whether or not you are overriding something before adding new values
to your data structure.

Arrays 6
ArrayLists
ArrayLists are very similar to arrays except for the fact that you can resize an arrayList.
They are also part of the List interface (we’ll learn more about interfaces later).
ArrayLists don’t have to have a specific size when you first initialize them - in fact, you
can initialize a completely empty array list with no values inside of it.

Introduction
Let’s look at an example. This time, our car dealership has an unlimited number of
parking spots in the garage. We can initilize the empty parking garage like so:

var cars = ArrayList<String>()

Or, we can add cars right away

val cars = arrayListOf("Volvo", "Porsche", "BMW", "Toyota", "Ford")

Using array list functions


Unlike an array, we actually have different functions we can use to access/remove/add
elements to our array list. Remember the functions we created a few modules back?
Well, lists have their own, predefined functions that we can use as well.

ArrayLists 1
Access Element by Value
To access the index of an element, we can use indexOf()

val cars = arrayListOf("Volvo", "Porsche", "BMW", "Toyota", "Ford")

var index = cars.indexOf("Porsche")


println("The Porsche is in Parking Spot " + index)

The output will look like this:

The Porsche is in Parking Spot 1

Access Element by index


To access an element using an index, we can use get()

val cars = arrayListOf("Volvo", "Porsche", "BMW", "Toyota", "Ford")

var car = cars.get(1)


println("The " + car + " is in Parking Spot 1")

The output will look like this:

The Porsche is in Parking Spot 1

Check size of arraylist


We can also check the size of the array list using size (just like an array)

ArrayLists 2
val cars = arrayListOf("Volvo", "Porsche", "BMW", "Toyota", "Ford")
var size = cars.size

println(size) // output = 5

Remove values
We can also remove a specific element using remove() or a specific element at an
index using removeAt(). Let’s look at an example:

val cars = arrayListOf("Volvo", "Porsche", "BMW", "Toyota", "Ford")


var size = cars.size

println(size) // output = 5

cars.remove("Porsche")
size = cars.size

println(size) // output = 4

Remember, with array lists, we can modify the size by removing and adding elements.
However, if we remove an element, we are also changing the index at which some of
the values exist. If we remove a value, all the values to the right will shift left.

Before:

["Volvo", "Porsche", "BMW", "Toyota", "Ford"]


//. 0 1 2 3 4

After:

["Volvo", "BMW", "Toyota", "Ford"]


//. 0 1 2 3

ArrayLists 3
We can also remove values by index

val cars = arrayListOf("Volvo", "Porsche", "BMW", "Toyota", "Ford")


var size = cars.size

println(size) // output = 5

cars.removeAt(1)
size = cars.size

println(size) // output = 4

The output will be the same as specified above.

Adding values
And what about adding values to an array list? Well, we can do that using the add()
functionality. Actually, this will add the element to the end of the list so we don’t have to
worry about moving indexes.

val cars = arrayListOf("Volvo", "Porsche", "BMW", "Toyota", "Ford")


var size = cars.size

println(size) // output = 5

cars.add("Tesla Model X")


size = cars.size

println(size) // output = 6

Before:

["Volvo", "Porsche", "BMW", "Toyota", "Ford"]


//. 0 1 2 3 4

ArrayLists 4
After:

["Volvo", "Porsche", "BMW", "Toyota", "Ford", "Tesla Model X"]


//. 0 1 2 3 4 5

We can also add values in a specific place in the array list (which will modify the
indexes)

val cars = arrayListOf("Volvo", "Porsche", "BMW", "Toyota", "Ford")


var size = cars.size

println(size) // output = 5

cars.add(2, "Tesla Model X")


size = cars.size

println(size) // output = 6

Before:

["Volvo", "Porsche", "BMW", "Toyota", "Ford"]


//. 0 1 2 3 4

After:

["Volvo", "Porsche", "Tesla Model X", "BMW", "Toyota", "Ford"]


//. 0 1 2 3 4 5

You can see here the the Tesla Model X is now on the 2nd index, while the other cars
have all shifted one index to the right (the cars to the right of the Tesla, at least).

ArrayLists 5
Iterating through an arraylist
And last but not least, we’ll want to iterate through our array list at certain points.
Whether it’s checking inventory or printing out all of the cars that we have - maybe a
customer wants to see the list of the cars that are available - we have a way to do that!
This is using a for each loop (similar to a for loop) it's just iterating through values in a
collection.

val cars = arrayListOf("Volvo", "Porsche", "BMW", "Toyota", "Ford")

for(car in cars){
println(car)
}

The output will look like this:

Volvo
Porsche
BMW
Toyota
Ford

So, there you have it! The most basic way to start using an array list!

ArrayLists 6
HashMaps
Ok, so we’ve talked about arrays and array lists, but what about hash maps? Well, before we get to
hash maps, let me explain something. Whether we are using a loop to find an element in an array or
array list, or if we are using the get() function to access an element, we are iterating through every
element in the array or array list before finding the value.

Now, if we have millions of cars in our inventory, it may take a maximum of a million tries to finally
find our car, right? Well, a hash map is one way we can better organize our data and even access it
faster than an array or array list.

Think of a hashmap like a dictionary. The hash map is made up of key/value pairs. For example,
when we’re searching for a word in a dictionary, we don’t just start from the first page and continue
looking through all of the pages until we find the word we’re looking for. Instead, we find the section
that starts with our word’s letter (for example, ‘C’ for ‘Cucumber’ - this is our key) and then
immediately open the section that starts with ‘C’. This narrows down our search quite a bit, but it
also takes more effort for us to organize the data well in the first place.

This is what a hash map looks like:

HashMaps 1
The key represents numbers in this case, while the values are names. The numbers could represent
a person’s age, their place in line, etc. But note that we can also put non-primitive types in our hash
map values (such as array lists).

Since we were talking about cars before, let’s continue with that example. Let’s say we want to
categorize our inventory based on price. Our keys will be an approximate price tier, and the values
will be a list of cars that fit that range.

Instead of iterating through an entire list of cars to find every single one that is part of a certain price
tier, we can categorically take the time to organize them within each tier first. Remember, this will
take more computing power up front, but will save a TON of time in accessing values more quickly.

Ok, let’s start with initializing an empty hash map. These will all be defined in the main function by
the way

val map = hashMapOf<Int, List<String>>()

the Int represents the data type for the key (price tier), and the List<String> represents the list of
cars associated with that price range.

Now, let’s start organizing our hash map by adding values to it. Either, we can start putting values
into an empty hashmap as such:

map.put(5000, listOf("2009 Toyota", "2013 Jeep Wrangler"))


map.put(10000, listOf("2019 Toyota", "2018 Jeep Wrangler"))
map.put(15000, listOf("2022 Subaru"))

println(map)

output:

{10000=[2019 Toyota, 2018 Jeep Wrangler], 5000=[2009 Toyota, 2013 Jeep Wrangler], 15000=[2022 Subaru]}

Or, we can initialize the hash map with values right away:

HashMaps 2
val map = hashMapOf(
5000 to listOf("2014 Toyota", "2009 Jeep Wrangler", "2012 Nissan Murano"),
10000 to listOf("2018 Toyota", "2012 Jeep Wrangler"),
25000 to listOf("2020 Nissan Murano"),
50000 to listOf("BMW", "Tesla Model Y", "Tesla Model X"),
100000 to listOf("Lamborghini", "Maserati", "Porsche")
)

So now we have a range of values associated with different price tiers. What if we want to list out all
of the cars in the price range of $50,000?

Well, we can use the get() function to retrieve all of the elements.

var carsFor50K = map.get(50000)


println(carsFor50K)

The output will look like:

[BMW, Tesla Model Y, Tesla Model X]

If you want to find a specific car within that list, we can also go back to our array list functions to find
a specific car.

//initialize map
val map = hashMapOf(
5000 to listOf("2014 Toyota", "2009 Jeep Wrangler", "2012 Nissan Murano"),
10000 to listOf("2018 Toyota", "2012 Jeep Wrangler"),
25000 to listOf("2020 Nissan Murano"),
50000 to listOf("BMW", "Tesla Model Y", "Tesla Model X"),
100000 to listOf("Lamborghini", "Maserati", "Porsche")
)

// find cars in the $50,0000 range


var carsFor50K = map.get(50000)

// check if Tesla Model X is part of the list using contains() function


if(carsFor50K != null){
if(carsFor50K.contains("Tesla Model X")) println("The dealership has a Tesla Model X for $50,000!!!")
}

HashMaps 3
The output will look like:

The dealership has a Tesla Model X for $50,000!!!

There are plenty of uses for hash maps, feel free to play around with this data structure as it can be
a very powerful tool!

HashMaps 4
Introduction to OOP
OOP stands for Object Oriented Programming. Up until now, we had been writing
procedural code - we would define variables and functions, and then execute them
chronologically in our main function. With OOP principles, we are organizing functions
and data within a class. A class is an abstract way of defining a general object. A class
can be pretty much anything - from an Animal, Athlete, Vehicle, etc. and those classes
can contain data such as a person's name, or the brand of a car. They can also hold
functions such as finding the age of a person, or determining the price of the car based
on its’ attributes.

Now, this gives us a way to organize our code a lot better, as well as re-use code (rather
than repeating ourselves and writing the same thing over and over again). We typically
use objects, which are instances of a class, to re-use the code. For example, we may
create a Fruit class. If we want to create an object of this class, we may initialize a Fruit
named Apple, or another Fruit named Peach.

Sound confusing? Well, let’s look at some visuals.

A class is basically a template for the objects we want to create. And instead of re-
creating the template over and over again, we just define each object as an instance of
the class itself. That way, any functions or variables we define inside of the class, gets
inherited by the object!

Introduction to OOP 1
Let’s brainstorm some values and functions that could be a part of the Fruit class.

A fruit would need a name (ie. apple, banana, mango, etc), a weight (in lbs), and a color
(orange, yellow, green, etc). Now what about functions? Could we possibly calculate the
price of the fruit based on its’ weight? And what about it’s seasonality? We can also
create a function to see which season the fruit is grown in!

Fruit class:

variables:
{name, weight, color}

functions:
{getPrice(), getSeason()}

Alright, let’s get started with some coding examples now that we’ve defined the Fruit
class! You can start to see how computer science is very creative as well - you could
define any number of classes to represent almost any type of object!

Introduction to OOP 2
Defining a Class and Creating
Objects
Let’s try to define a class. Using the same variables we defined before, ie. name,
weight, and color, we can initialize each value as an empty string or 0, because once we
create an object using this class, that’s when we can give these variables actual
values.

Create a class
Here is an example of the Fruit class. Simple, right?

class Fruit{
var name = ""
var weight = 0.0
var color = ""
}

Up until now, we had been coding inside of our main function. Pro tip: we actually define
classes outside of our main function. We can even define them in separate files, but for
the sake of this lesson, we’ll define everything inside the same file for simplicity.

class Fruit{
var name = ""
var weight = 0.0
var color = ""
}

// define the main function here


fun main(){

Defining a Class and Creating Objects 1


Create an instance
Now how do we create an object of this class? Well, we can define at as such in our
main function.

class Fruit{
var name = ""
var weight = 0.0
var color = ""
}

// define the main function here


fun main(){
var apple = Fruit()
}

We’ve gone ahead and created a Fruit called apple. But our apple doesn’t have it’s
name, weight, or color defined. Let’s go ahead and define those values.

class Fruit{
var name = ""
var weight = 0.0
var color = ""
}

// define the main function here


fun main(){
var apple = Fruit()

apple.name = "apple"
apple.weight = 0.45
apple.color = "red"

println(apple.name)
println(apple.weight)
println(apple.color)
}

The output will look like this:

apple
0.45
red

Defining a Class and Creating Objects 2


We can actually create as many instances of the Fruit class as we’d like. Let’s try that
out.

class Fruit{
var name = ""
var weight = 0.0
var color = ""
}

// define the main function here


fun main(){
var apple = Fruit() // first instance

apple.name = "apple"
apple.weight = 0.45
apple.color = "red"

var banana = Fruit() // second instance

banana.name = "banana"
banana.weight = 0.65
banana.color = "yellow"
}

So, here you can see that we have two completely separate instances of a fruit, with the
same exact type of properties, but with different values. We are using a template for
these different fruits and re-using that template anytime we want to define a type of fruit.

Constructors
And what if we wanted a faster way of initializing each object’s properties? Instead of
creating an instance and then defining each property ie. name, weight, and color of a
fruit afterwards in the main function, we can actually use something called a constructor
to define those properties right away.

A constructor is similar to a function, and it’s denoted by using parenthesis () after the
class name. You can specify the properties inside of the parenthesis (kind of like
passing parameters into a regular function).

Defining a Class and Creating Objects 3


The constructor will initialize the properties whenever you create an object of a class.
Just don’t forget to add the variable type (and name) in the constructor.

Let’s look at an example. Define the class like this:

class Fruit(var name: String, var weight: Double, var color: String)

// define the main function here


fun main(){

var apple = Fruit("apple", 0.45, "red") // first instance


var banana = Fruit("banana", 0.65, "yellow") // second instance

We can still access each fruit’s properties as we did before as well

class Fruit(var name: String, var weight: Double, var color: String)

// define the main function here


fun main(){

var apple = Fruit("apple", 0.45, "red") // first instance


var banana = Fruit("banana", 0.65, "yellow") // second instance

println(apple.name)
println(banana.name)

The output will look like this:

apple
banana

Defining a Class and Creating Objects 4


Add functions to class
Ok, so let’s wrap up the class by adding some functions as mentioned in the intro.

We’re going to add the getPrice() function first. We will define the function just as we’ve
defined functions before, except this time it’ll be inside of the class itself. And for our
input, we’ll actually use the weight that is already defined inside of the class as well.

class Fruit(var name: String, var weight: Double, var color: String){

// get price of fruit


fun getPrice(): Double = weight * .85

The getPrice() function is using the weight (which has been passed in through the
constructor when initializing the object) to determine the price of the fruit. We can also
define a seasonality function to return the season that the fruit is usually grown in.

We’re going to create a function that has a hashmap of fruits (key), associated with a list
of seasons (value). We can use the fruit name to find the list of seasons and return it as
such. Also, don’t forget to do a null check just in case your fruit doesn’t exist in the hash
map. You’ll need a backup of sorts - in our case, we’ll return an arraylist with an empty
string.

Defining a Class and Creating Objects 5


class Fruit(var name: String, var weight: Double, var color: String){

// get price of fruit


fun getPrice(): Double = weight * .85

// get season of fruit


fun getSeasons(): List<String> {
var seasons = hashMapOf(
"apple" to listOf("Fall"),
"banana" to listOf("Spring", "Summer"),
"carrots" to listOf("Summer"),
"strawberries" to listOf("Spring, Summer, Fall"),
)

// make sure to do a null check in case your fruit doesn't exist


// in the hash map
var seasonsOfFruit = seasons.get(name)

if (seasonsOfFruit != null) {
return seasonsOfFruit
} else {
return arrayListOf("")
}
}
}

Now that we’ve defined our 2 functions, let’s create instances in the main function and
use these functions that we’ve just defined. (You can literally copy/paste this code to
see the results run in your own IDE - just a check in to make sure you're coding along
side me )

// define Fruit class


class Fruit(var name: String, var weight: Double, var color: String){

// get price of fruit


fun getPrice(): Double = weight * .85

// get season of fruit


fun getSeasons(): List<String> {
var seasons = hashMapOf(
"apple" to listOf("Fall"),
"banana" to listOf("Spring", "Summer"),
"carrots" to listOf("Summer"),
"strawberries" to listOf("Spring, Summer, Fall"),

Defining a Class and Creating Objects 6


)

var seasonsOfFruit = seasons.get(name)

if (seasonsOfFruit != null) {
return seasonsOfFruit
} else {
return arrayListOf("")
}
}
}

// define the main function here


fun main(){

// create instances of fruit


var apple = Fruit("apple", 0.45, "red") // first instance
var banana = Fruit("banana", 0.65, "yellow") // second instance

// use the getPrice() function to compare prices of 2 fruits


if(apple.getPrice() >= banana.getPrice()) {
println("Bananas are cheaper than apples")
} else {
println("Apples are cheaper than bananas")
}

// use the getSeasons() function to list all the seasons


println("Apples grow in the following seasons: " + apple.getSeasons())
println("Bananas grow in the following seasons: " + banana.getSeasons())

The output will look like this

Apples are cheaper than bananas


Apples grow in the following seasons: [Fall]
Bananas grow in the following seasons: [Spring, Summer]

And actually, we can create this in a more efficient way by removing the hash map from
the getSeasons() function and just define the hash map inside of the class itself. That
way, we won’t initialize and populate a new hash map every time we call the
getSeasons() function, but only when we first initialize the object!

Defining a Class and Creating Objects 7


// define Fruit class
class Fruit(var name: String, var weight: Double, var color: String){

// initialize seasons hashmap


var seasons = hashMapOf(
"apple" to listOf("Fall"),
"banana" to listOf("Spring", "Summer"),
"carrots" to listOf("Summer"),
"strawberries" to listOf("Spring, Summer, Fall"),
)

// get price of fruit


fun getPrice(): Double = weight * .85

// get season of fruit


fun getSeasons(): List<String> {
var seasonsOfFruit = seasons.get(name)

if (seasonsOfFruit != null) {
return seasonsOfFruit
} else {
return arrayListOf("")
}
}
}

// define the main function here


fun main(){

// create instances of fruit


var apple = Fruit("apple", 0.45, "red") // first instance
var banana = Fruit("banana", 0.65, "yellow") // second instance

// use the getPrice() function to compare prices of 2 fruits


if(apple.getPrice() >= banana.getPrice()) {
println("Bananas are cheaper than apples")
} else {
println("Apples are cheaper than bananas")
}

// use the getSeasons() function to list all the seasons


println("Apples grow in the following seasons: " + apple.getSeasons())
println("Bananas grow in the following seasons: " + banana.getSeasons())

As you start to create classes and instantiate them, you’ll start to see how useful OOP
can be when trying to re-use code over and over again. In this case, we defined the fruit

Defining a Class and Creating Objects 8


class once, as well as the getSeasons() functionality as well. That function in particular
was a bit long, so it’s a good thing we don’t have to continuously write the code for this
for every single object that we create. But this also means that this function is only part
of the Fruit class, rather than it just being an openly available function. We have to
create an instance of the Fruit class FIRST before we can even use that function.

Defining a Class and Creating Objects 9


Create a Football Player Class
Alright, so we just learned about classes and objects - this topic can be a little
confusing, so we’re going to take a bit of time to create another class from scratch to get
used to this new concept, and what better way to do that than with football players
(sorry everyone from the US - I'm talking about soccer players if you’re wondering).

Let’s brainstorm what a football player class could look like. What kind of properties
would a football player have? Maybe a name, height, position, team, total games
played, total goals made, and number of assists made. Let’s start with these properties -
we can always add more later.

Create the football player class


This is what the Football player class might look like

class FootballPlayer (
var name: String,
var team: String,
var position: String,
var height: Double,
var totalGamesPlayed: Int,
var totalGoalsMade: Int,
var numberOfAssistsMade: Int)

We’ve gone ahead and created a constructor with the properties mentioned above. Now
what about functions that could be part of the Football player class? Well, a football
player can kick a ball, pass a ball, they might have an average number of goals per
game, or even a typical pass percentage. Let's start out with these functions for now.

Add a Kick() and Pass() function


Let’s start with adding a kick() and pass() function. These functions can do something
simple such as print “{football player name} kicked the ball” to the console.

Create a Football Player Class 1


class FootballPlayer (
var name: String,
var team: String,
var position: String,
var height: Double,
var totalGamesPlayed: Int,
var totalGoalsMade: Int,
var numberOfAssistsMade: Int) {

// kick the ball


fun kick(){
println(name + " kicked the ball!")
}

// pass the ball


fun pass(){
println(name + " passed the ball!")
}
}

Let’s take a pause and create a few football player objects in the main function before
we start adding more functions to the football player class

class FootballPlayer(
var name: String,
var team: String,
var position: String,
var height: Double,
var totalGamesPlayed: Int,
var totalGoalsMade: Int,
var numberOfAssistsMade: Int)
{
// kick the ball
fun kick(){
println(name + " kicked the ball!")
}

// pass the ball


fun pass(){
println(name + " passed the ball!")
}
}

Create a Football Player Class 2


fun main() {

// create instance of the football player class


var Ronaldo = FootballPlayer(
"Cristiano Ronaldo", "Portugal", "Forward", 165.5, 170, 287, 112)

// print player's name and total goals scored


println("The player's name is " + Ronaldo.name)
println("The player's total goals scored are " + Ronaldo.totalGoalsMade)

// call the kick and pass function


Ronaldo.kick()
Ronaldo.pass()
}

The result looks like this

The player's name is Cristiano Ronaldo


The player's total goals scored are 287
Cristiano Ronaldo kicked the ball!
Cristiano Ronaldo passed the ball!

Great! As you can see, we’ve created an instance of the Football class and called its’
functions kick() and pass(). Well, what about adding a couple functions that do more
than just print a line to the console? We could also add a function such as
averageGoalsPerGame() - we have the total goals and total games played for each
player. We could also make a function for averageAssistsPerGame(). Let’s try that out!

class FootballPlayer(
var name: String,
var team: String,
var position: String,
var height: Double,
var totalGamesPlayed: Int,
var totalGoalsMade: Int,
var numberOfAssistsMade: Int)
{
// kick the ball
fun kick(){
println(name + " kicked the ball!")
}

Create a Football Player Class 3


// pass the ball
fun pass(){
println(name + " passed the ball!")
}

// average goals per game


fun averageGoalsPerGame() : Int {
return totalGoalsMade/totalGamesPlayed
}

// average assists per game


fun averageAssistsPerGame() : Int {
return numberOfAssistsMade/totalGamesPlayed
}
}

Okay, let’s try to use these functions for our Renaldo object that we’ve created.

class FootballPlayer(
var name: String,
var team: String,
var position: String,
var height: Double,
var totalGamesPlayed: Int,
var totalGoalsMade: Int,
var numberOfAssistsMade: Int)
{
// kick the ball
fun kick(){
println(name + " kicked the ball!")
}

// pass the ball


fun pass(){
println(name + " passed the ball!")
}

// average goals per game


fun averageGoalsPerGame() : Int {
return totalGoalsMade/totalGamesPlayed
}

// average assists per game


fun averageAssistsPerGame() : Int {
return numberOfAssistsMade/totalGamesPlayed
}
}

fun main() {

Create a Football Player Class 4


// create instance of the football player class
var Ronaldo = FootballPlayer(
"Cristiano Ronaldo", "Portugal", "Forward", 165.5, 170, 287, 112)

// print player's name and total goals scored


println("The player's name is " + Ronaldo.name)
println("The player's total goals scored are " + Ronaldo.totalGoalsMade)

// call the kick and pass function


Ronaldo.kick()
Ronaldo.pass()

var avgGoalsPerGame = Ronaldo.averageGoalsPerGame()


var avgAssistsPerGame = Ronaldo.averageAssistsPerGame()

println("Ronaldo scores an average of "


+ avgGoalsPerGame + ", and has an average of "
+ avgAssistsPerGame + " assists per game!")
}

The output will look something like this

The player's name is Cristiano Ronaldo


The player's total goals scored are 287
Cristiano Ronaldo kicked the ball!
Cristiano Ronaldo passed the ball!
Ronaldo scores an average of 1, and has an average of 0 assists per game!

As you can see, we used the total goals scored (287) divided by total games played
(170). Because we are working with integers, when we divide two integers, we usually
round down to the next whole number. So, in this case, 287/170 = 1.68. Technically, this
is closer to 2 than it is 1 .. but with integers, the rule is to round down. If we look at the
assists, we can also see that he has an average of 0 assists per game .. which isn’t
giving us an accurate representation of his assisting contributions. For both of these
cases, we can try to work with Doubles instead of Integers. Let’s change our functions
accordingly.

Create a Football Player Class 5


class FootballPlayer(
var name: String,
var team: String,
var position: String,
var height: Double,
var totalGamesPlayed: Double,
var totalGoalsMade: Double,
var numberOfAssistsMade: Double)
{
// kick the ball
fun kick(){
println(name + " kicked the ball!")
}

// pass the ball


fun pass(){
println(name + " passed the ball!")
}

// average goals per game


fun averageGoalsPerGame() : Double {
return totalGoalsMade/totalGamesPlayed
}

// average assists per game


fun averageAssistsPerGame() : Double {
return numberOfAssistsMade/totalGamesPlayed
}
}

fun main() {

// create instance of the football player class


var Ronaldo = FootballPlayer(
"Cristiano Ronaldo", "Portugal", "Forward", 165.5, 170.0, 287.0, 112.0)

// print player's name and total goals scored


println("The player's name is " + Ronaldo.name)
println("The player's total goals scored are " + Ronaldo.totalGoalsMade)

// call the kick and pass function


Ronaldo.kick()
Ronaldo.pass()

var avgGoalsPerGame = Ronaldo.averageGoalsPerGame()


var avgAssistsPerGame = Ronaldo.averageAssistsPerGame()

println("Ronaldo scores an average of "


+ avgGoalsPerGame + ", and has an average of "
+ avgAssistsPerGame + " assists per game!")
}

Create a Football Player Class 6


After modifying our constructor, the return types for our functions, and the input values
when instantiating our Renaldo object, here’s what we get as the output:

The player's name is Cristiano Ronaldo


The player's total goals scored are 287.0
Cristiano Ronaldo kicked the ball!
Cristiano Ronaldo passed the ball!
Ronaldo scores an average of 1.688235294117647,
and has an average of 0.6588235294117647 assists per game!

This is a much better representation of the player’s average scoring and assist
breakdown!

Now, we’re going to add one last function that actually helps modify the players values
that they were originally initialized with. For example, Ronaldo’s totalGoalsMade is a
fixed number that we set when we first create the object. But what If we created a
score() function that increases his score count? Or a passToScore() function that
increases his assist count? We can use these functions to receive a true or false value
which will help us determine whether or not we should increase the count.

For example

fun score(playerHasScored : Boolean){


if(playerHasScored){
totalGoalsMade++
println(name + " has scored!")
} else {
println(name + " has not scored :(")
}
}

the ‘totalGoalsMade’ is a property of the FootballPlayer class, so we can always modify


this value. The ‘name’ value is also used here in the println() statement. Again, this

Create a Football Player Class 7


value is also specific to the class we are creating the function inside of (this is why we
don’t need to use Renaldo.totalGoalsMade or Renaldo.name). We only reference the
object if we’ve instantiated it (ie. in the main function).

Ok, let’s add the passToScoreFunction()

fun assist(playerHasAssisted : Boolean){


if(playerHasAssisted){
totalAssistsMade++
println(name + " has assisted a goal!")
} else {
println(name + " has not assisted a goal :(")
}
}

Here’s what it looks like altogether

class FootballPlayer(
var name: String,
var team: String,
var position: String,
var height: Double,
var totalGamesPlayed: Double,
var totalGoalsMade: Double,
var numberOfAssistsMade: Double)
{
// kick the ball
fun kick(){
println(name + " kicked the ball!")
}

// pass the ball


fun pass(){
println(name + " passed the ball!")
}

// average goals per game


fun averageGoalsPerGame() : Double {
return totalGoalsMade/totalGamesPlayed
}

// average assists per game


fun averageAssistsPerGame() : Double {
return numberOfAssistsMade/totalGamesPlayed

Create a Football Player Class 8


}

// player increments number of goals


fun score(playerHasScored : Boolean){
if(playerHasScored){
totalGoalsMade++
} else {
println(name + " has not scored :(")
}
}

// player increments number of assists


fun assist(playerHasAssisted : Boolean){
if(playerHasAssisted){
numberOfAssistsMade++
} else {
println(name + " has not assisted a goal :(")
}
}
}

Ok, let’s try to call these functions:

fun main() {

// create instance of the football player class


var Ronaldo = FootballPlayer(
"Cristiano Ronaldo", "Portugal", "Forward", 165.5, 170.0, 287.0, 112.0)

// print player's name and total goals scored


println("The player's name is " + Ronaldo.name)
println("The player's total goals scored are " + Ronaldo.totalGoalsMade)
println("The player's total assists made are " + Ronaldo.numberOfAssistsMade)

// get average goals and assists per game


var avgGoalsPerGame = Ronaldo.averageGoalsPerGame()
var avgAssistsPerGame = Ronaldo.averageAssistsPerGame()

println("Ronaldo scores an average of "


+ avgGoalsPerGame + ", and has an average of "
+ avgAssistsPerGame + " assists per game!")

// player scores 12 times


for(i in 0..11){
Ronaldo.score(true)
}

// player assists 320 times


for(i in 0..319){

Create a Football Player Class 9


Ronaldo.assist(true)
}

// Let's re-check the values to see if anything has changed


println("The player's total goals scored are " + Ronaldo.totalGoalsMade)
println("The player's total assists made are " + Ronaldo.numberOfAssistsMade)

// get average goals and assists per game


avgGoalsPerGame = Ronaldo.averageGoalsPerGame()
avgAssistsPerGame = Ronaldo.averageAssistsPerGame()

println("Ronaldo scores an average of "


+ avgGoalsPerGame + ", and has an average of "
+ avgAssistsPerGame + " assists per game!")

The output will look like this

The player's name is Cristiano Ronaldo


The player's total goals scored are 287.0
The player's total assists made are 112.0
Ronaldo scores an average of 1.688235294117647,
and has an average of 0.6588235294117647 assists per game!
The player's total goals scored are 299.0
The player's total assists made are 432.0
Ronaldo scores an average of 1.7588235294117647,
and has an average of 2.541176470588235 assists per game!

So you can see that we’ve not only modified that player’s values, but also his average
scoring and assisting per game as well. Hopefully this will give you a good
understanding of how to define a class and utilize functions to modify values inside of
the class. Using these steps, try to create an entirely new class from scratch. In fact, try
to create two different types of classes and instantiate both of them in the main function.

Create a Football Player Class 10


Abstract Classes and Interfaces
Now that we've learned about Classes and creating objects, we're going to dive a bit deeper into Inheritance .
Inheritance is just a fancy term to describe a subclass being a part of a superclass and inheriting many of its' properties
and/or functions. Today, we're going to focus on abstract classes and interfaces, so let's get started!

Abstract Class
An abstract class is kind of like a parent class to a sub class. An example would be a Dog sub class that is part of the
Animal super (parent) class. However, abstract classes can't be instantiated. Remember in the previous lessons how
we created an object out of a class? This gave us an opportunity to recycle the code for each class and re-create much
of the functionality without redefining methods and variables.

Well, with abstract classes, we can't exactly do that. Instead, we can create these classes to define the fields and
functionality of any sub-class that inherits from this parent class. It gives us a more structured way to organize the
types of classes that are in our codebases and how they are all associated or linked with each other.

Abstract Classes and Interfaces 1


As you can see in this diagram, we have an abstract class called Animal and subclasses that extend this class called
Human, Frog, Millipede. Now, we've defined a getLegs(), feed, and isAnimal() function(s) inside of the Animal abstract
class. This just means that all sub-classes that extend this class will inherit the functions (or variables) that are defined
here. They may even use the same functionality defined in the Animal abstract class, or they can override the
functionality by creating their own logic for the methods.

Ok, enough talk, let's look at some examples to understand this further. We're going to build off our previous examples
with the Football player class. Here is an example of an abstract class called Athlete. We've defined the fields name,
sport, and country for the Athlete. Now, this means that any sub class that extends the Athlete class will also have those
fields. Likewise, the getBio() function will also be inherited by the Athlete's sub classes.

abstract class Athlete(


val name: String,
val sport: String,
val country: String
) {
fun getBio() {
println(name + " plays " + sport + " for " + country)
}
}

Let's look at an example of how to format the Football player class so that it can extend the Athlete abstract class.
We still have methods that are specific to the Football player class, like kick(), averageGoalsPerGame(), and
averageAssistsPerGame() , but we've also included country and sport as part of the constructor because it is used in
the Athlete abstract class. Not only that, but we've used the syntax :Athlete(name, sport, country) as a way to show
A) we are extending from the Athlete class, but also B) we are passing the values name, country, and sport to the
Athlete abstract class from the constructor of the Football Player class to use for any of its' functions as well.

class FootballPlayer(
name: String,
country: String,
sport: String,
var totalGamesPlayed: Int,
var totalGoalsMade: Int,

Abstract Classes and Interfaces 2


var numberOfAssistsMade: Int
) : Athlete(name, sport, country) {

// kick the ball


fun kick() {
println("$name kicked the ball!")
}

// average goals per game


fun averageGoalsPerGame(): Float {
return totalGoalsMade.toFloat() / totalGamesPlayed
}

// average assists per game


fun averageAssistsPerGame(): Float {
return numberOfAssistsMade.toFloat() / totalGamesPlayed
}
}

This is what our main method would look like. As you can see, we've passed the two new parameters into the Football
player class, but we've also called ronaldo.getBio() because the getBio() function is also available for the Football
player class to use. Even though this function isn't part of the Football player class, it's part of the Athlete abstract class
that is extended by the Football player class, ie. inheritance!

fun main() {
// create instance of the football player class
val ronaldo = FootballPlayer(
"Cristiano Ronaldo",
"Portugal",
"Football",
100,
75,
50
)

// print player's name and total goals scored


println("The player's name is ${ronaldo.name}")
println("The player's total goals scored are ${ronaldo.totalGoalsMade}")

// call the kick function


ronaldo.kick()
ronaldo.getBio()

val avgGoalsPerGame = ronaldo.averageGoalsPerGame()


val avgAssistsPerGame = ronaldo.averageAssistsPerGame()

println("Ronaldo scores an average of $avgGoalsPerGame goals, and has an average of $avgAssistsPerGame assists per game!")
}

Here is the output

The player's name is Cristiano Ronaldo


The player's total goals scored are 75
Cristiano Ronaldo kicked the ball!
Cristiano Ronaldo plays Football for Portugal
Ronaldo scores an average of 0.75 goals, and has an average of 0.5 assists per game!

Abstract Classes and Interfaces 3


So why wouldn't we just define getBio() in the Football player class? What's the point of having another class - doesn't
it just make it more confusing? Well, this goes along with our need to be “lazy” engineers. Abstract classes are typically
used when we have more than one subclass that is extending the abstract class. That way, we don't have to create the
same function in the sub classes over and over again, we can actually share functions between classes if they are all of
the same super class (while still having their own unique fields and functions as well).

An example would be using a BasketballPlayer class that extended our Athlete abstract class. As you can see, we
still need to pass some of the same values as the Football Player class (specifically any values needed by the Athlete
abstract class, which happen to be a name, sport, and country)

class BasketballPlayer(
name: String,
country: String,
sport: String,
var totalGamesPlayed: Int,
var totalBasketsMade: Int
) : Athlete(name, sport, country) {

// kick the ball


fun score() {
println("$name scored a basket!")
}

// average goals per game


fun averageBasketsPerGame(): Float {
return totalBasketsMade.toFloat() / totalGamesPlayed
}
}

In the main method, we can actually still call getBio() for both the Football Player class and the Basketball player class
(without re-writing the code). For now, it doesn't make a huge difference , but you can imagine if we have several
functions shared between many different sub-classes, it would be helpful to have that code consolidated in one place.

fun main() {
// create instance of the football player class
val ronaldo = FootballPlayer(
"Cristiano Ronaldo",
"Portugal",
"Football",
100,
75,
50
)

val leBron = BasketballPlayer(


"LeBron James",
"USA",
"Basketball",
1000,
7500
)

// print player's name and total goals scored


println("The player's name is ${ronaldo.name}")
println("The player's total goals scored are ${ronaldo.totalGoalsMade}")

// call the kick function


ronaldo.kick()
ronaldo.getBio()

// here we can call the getBio() function for LeBron as well

Abstract Classes and Interfaces 4


leBron.getBio()

val avgGoalsPerGame = ronaldo.averageGoalsPerGame()


val avgAssistsPerGame = ronaldo.averageAssistsPerGame()

println("Ronaldo scores an average of $avgGoalsPerGame goals, and has an average of $avgAssistsPerGame assists per game!")
}

Here's the output

The player's name is Cristiano Ronaldo


The player's total goals scored are 75
Cristiano Ronaldo kicked the ball!
Cristiano Ronaldo plays Football for Portugal
LeBron plays Basketball for USA
Ronaldo scores an average of 0.75 goals, and has an average of 0.5 assists per game!

Now, here's where it gets a little tricky. We can inherit these functions and variables, but we can also inherit abstract
functions and variables. All this means, is that these values are defined in the abstract class but they are implemented
(or overridden) in the sub-class that extends it. And any abstract function defined in the abstract class (or abstract
variable) HAVE to be implemented in all of the sub classes. This is useful for just organizing your code so it can be
defined in a certain way. Let's look at an example by modifying the Athlete abstract class

abstract class Athlete(


val name: String,
val sport: String,
val country: String
) {
fun getBio() {
println(name + " plays " + sport + " for " + country)
}

abstract fun isGoodPlayer(gamesPlayed: Int, points: Int): Boolean


}

As you can see above, we've added the isGoodPlayer abstract function, while defining it's input parameters and output
data type. However, we have not added any logic to the function. This function needs to be overridden in the sub
class(es) like so:

class FootballPlayer(
name: String,
country: String,
sport: String,
var totalGamesPlayed: Int,
var totalGoalsMade: Int,
var numberOfAssistsMade: Int
) : Athlete(name, sport, country) {

// kick the ball


fun kick() {
println("$name kicked the ball!")
}

// average goals per game

Abstract Classes and Interfaces 5


fun averageGoalsPerGame(): Float {
return totalGoalsMade.toFloat() / totalGamesPlayed
}

// average assists per game


fun averageAssistsPerGame(): Float {
return numberOfAssistsMade.toFloat() / totalGamesPlayed
}

// overridden function
override fun isGoodPlayer(gamesPlayed: Int, points: Int): Boolean {
if(points/gamesPlayed>=1){
return true
}
return false
}
}

So we've added the isGoodPlayer() function to the FootballPlayer class but we've defined it in a way where it would fit
the class. A Football Player might be defined as “good” If they score at least 1 goal per game. But if we used that same
logic for a Basketball player, that wouldn't make sense. So, we use abstract functions and variables when we know that
all the sub-classes have to use those values/functions, but they won't necessarily use the same logic between all the
sub-classes. Let's look at an example for the Basketball player class using the isGoodPlayer() function.

As you can see, we've given this overridden function an average of 15 points per game for a basket player to be
considered a good player. The Football and Basketball Player classes are using the same function, but different logic.

class BasketballPlayer(
name: String,
country: String,
sport: String,
var totalGamesPlayed: Int,
var totalBasketsMade: Int
) : Athlete(name, sport, country) {

// kick the ball


fun score() {
println("$name scored a basket!")
}

// average goals per game


fun averageBasketsPerGame(): Float {
return totalBasketsMade.toFloat() / totalGamesPlayed
}

// overridden function
override fun isGoodPlayer(gamesPlayed: Int, points: Int): Boolean {
if(points/gamesPlayed>=15){
return true
}
return false
}
}

Eventually, with more practice (trial and error) this strange concept of inheritance and sub/super classes will start to
make sense. Now, let's move onto interfaces!

Abstract Classes and Interfaces 6


Interfaces
Interfaces are similar to abstract classes. In Kotlin, they can contain declarations of abstract methods, as well as
method implementations. But the biggest difference between abstract classes and interfaces is that interfaces cannot
store state. They can have properties, but these need to be abstract or provide accessor implementations.

Let's look at an example!

interface Person {

var retired: Boolean // abstract property

fun wave() // abstract method


fun hello() = "Hello there" // method with default implementation
}

As you can see above, all variables that are defined without values are just considered abstract properties or methods.
With the hello() function, it has a default implementation (which can still be overridden by sub-classes) that returns the
string “Hello there”.

Let's look at how we would use this in the Football Player Class. We've added the overridden retired variable and
wave function, while implementing the logic for both. Because the hello() function has already been implemented in the
interface, we can also just use this instead of re-defining it.

class FootballPlayer(
name: String,
country: String,
sport: String,
var totalGamesPlayed: Int,
var totalGoalsMade: Int,
var numberOfAssistsMade: Int
) : Athlete(name, sport, country), Person { // we've also implemented Person here

// overridden retired variable


override var retired = false

// kick the ball


fun kick() {
println("$name kicked the ball!")
}

// average goals per game


fun averageGoalsPerGame(): Float {
return totalGoalsMade.toFloat() / totalGamesPlayed
}

// average assists per game


fun averageAssistsPerGame(): Float {
return numberOfAssistsMade.toFloat() / totalGamesPlayed
}

// overridden function
override fun isGoodPlayer(gamesPlayed: Int, points: Int): Boolean {
if(points/gamesPlayed>=1){
return true
}
return false
}

Abstract Classes and Interfaces 7


override fun wave() = println(name + " waved") // overridden wave function
}

Let's look at how it works in the main function.

fun main() {
// create instance of the football player class
val ronaldo = FootballPlayer(
"Cristiano Ronaldo",
"Portugal",
"Football",
100,
75,
50
)

// print player's name and total goals scored


println("The player's name is ${ronaldo.name}")
println("The player's total goals scored are ${ronaldo.totalGoalsMade}")

// call the kick function


ronaldo.kick()
ronaldo.getBio()

val avgGoalsPerGame = ronaldo.averageGoalsPerGame()


val avgAssistsPerGame = ronaldo.averageAssistsPerGame()

ronaldo.wave()
ronaldo.hello()

println("Ronaldo scores an average of $avgGoalsPerGame goals, and has an average of $avgAssistsPerGame assists per game!")
}

Here's what the output looks like:

The player's name is Cristiano Ronaldo


The player's total goals scored are 75
Cristiano Ronaldo kicked the ball!
Cristiano Ronaldo plays Football for Portugal
Ronaldo waved
Hello There!
Ronaldo scores an average of 0.75 goals, and has an average of 0.5 assists per game!

Phew! Hopefully this makes more sense. Please make sure to practice the example problems provided as this section
of the course can be a bit more difficult to understand! Glad you stuck with it!

Abstract Classes and Interfaces 8


Intro to Functional Programming
Functional Programming uses high-order functions to perform computations on variables or collections of items.
A higher-order function is a function that takes functions as parameters, or returns a function. We learned about
Object Oriented Programming earlier, where we can create classes and organize our code in a way that's
recyclable. Well, with functional programming (and lambdas) we are actually coding in a more .. well, functional,
way. We are using functions in a chronological way to manipulate the data, rather than spending too much time
organizing the code into several classes and super classes. There are pros and cons to using both, and you can
certainly intertwine both as well.

Let's look at a couple examples. Let's say we want to create a function to add 2 numbers. Usually, we can do
something like this:

fun addNumbers(x: Int, y: Int) {


return x + y
}

or

fun addNumbers(x: Int, y: Int) = x + y

Well, with lambda expressions, we can do something like this:

fun main(){

val addNumbers = { x: Int, y: Int -> x + y }


val result = addNumbers(3, 4)

println(result)
}

We've created a function addNumbers that takes two parameters of type: Int, and it returns the sum of both
numbers. As you can see, this is a high ordered function because we are adding the function itself in the
parameter of the definition of the sum function. Again, just another way to create a function in a more concise
way.

Higher-Order and Lambdas


Let's look at some more examples. This one calculates te result of two values, but you have to also pass the
operation type as a parameter in the function in order to calculate the result. This isn't just adding numbers, it's
taking 2 numbers and doing whatever you want to them!

Intro to Functional Programming 1


fun calculate(x: Int, y: Int, operation: (Int, Int) -> Int): Int {
return operation(x, y)
}

fun main() {
val sum = calculate(5, 3) { a, b -> a + b } // add two numbers
val difference = calculate(5, 3) { a, b -> a - b } // subtract one number

println("Sum: $sum")
println("Difference: $difference")
}

We can also do something like this:

fun calculate(x: Int, y: Int, operation: (Int, Int) -> Int): Int {
return operation(x, y)
}

fun main() {
val multiply = calculate(5, 3) { a, b -> a * b }
val expression = calculate(5, 3) { a, b -> (2*a) + (3*b) }

println("Multiplied values: $multiply")


println("Expression result: $expression")
}

These are actually higher order functions that take two integers AND a lambda function as a set of parameters.
Inside the calculate function, we invoke the operation lambda to perform the desired operation and return the
result. In the main function, we demonstrate the usage of calculate by passing different lambda expressions to
perform addition and subtraction.

Filter Function
We can also use functions such as map and filter on collections. Filter actually helps us be more selective with
values in a collection by specifying what we want removed (or what we want to keep)

fun main() {
val numbers = listOf(1, 2, 3, 4, 5)

val evenNumbers = numbers.filter { it % 2 == 0 }


println("Even numbers: $evenNumbers")

As you can see, we've used the modulus to filter numbers in the numbers list based on if they are divisible by 2
(or even). Using the filter function, we can easily keep only the values we want. Another example is, let's say we
have a collection of names, but we want to filter names based on if they start with a 'P' or an 'S'.

Intro to Functional Programming 2


fun main() {
val names = listOf("Paul", "Patrick", "Liza", "Elaine", "Sara", "Pooja", "Samuel", "Zane")

val filteredList = names.filter { it.startsWith('S', ignoreCase = true) || it.startsWith('P', ignoreCase = true) }

println("Filtered names starting with 'P' or 'S': $filteredList")


}

The example above shows us how we can quickly filter values in a collection (regardless of type), as long as we
are being explicit with the type of operation we want to use.

Map Function
Let's look at an example using map as well

fun main() {
val numbers = listOf(1, 2, 3, 4, 5)

val squaredNumbers = numbers.map { it * it }


println("Squared numbers: $squaredNumbers")
}

Here you can see that instead of filtering the values in the collection, we are manipulating them so that each
number now becomes the square of itself. The output would look like this:

Squared numbers: [1, 4, 9, 16, 25]

Instead of

[1, 2, 3, 4, 5]

we've converted the list to all squares of themselves.

Reduce Function
Lastly, you can also use the reduce function to reduce a collection of elements into a single value. This could be
useful if you have a list of expenses and you are trying to calculate the total for your expenses that month.

Intro to Functional Programming 3


Let's look at an example! Here you can see that we're using reduce to just add up all the numbers in the
numbers list.

fun main() {
val numbers = listOf(1, 2, 3, 4, 5)

val sum = numbers.reduce { acc, number -> acc + number }

println("Sum: $sum")
}

The output would be something like:

Sum: 15

Now, what if we want to filter be even numbers and then add up the rest of the numbers? Well , let's combine
the filter and reduce functions.

fun main() {
val numbers = listOf(1, 2, 3, 4, 5)

val sum = numbers.filter { it % 2 == 0 }.reduce { acc, number -> acc + number }

println("Sum: $sum")
}

Now our output is

Sum: 6

Because we are removing 1,3, and 5 from the list (they are odd), and then we are summing up the rest of the
numbers, our result will be a bit different this time around. There are more high-order functions and lambda
expressions that you can learn to use over time, but these are probably the most basic usage - something that
you can easily get started with right away!

Intro to Functional Programming 4

You might also like