In this section, we will learn about the scope of variables in Kotlin.
Definition of Scope: What Does Scope Mean for Kotlin Variables?
Scope of a variable is the area where a variable is accessible!
For example, if you declare a variable inside the body of a function, that variable is not accessible within the body of another function!
But if you declare a variable outside of the body of any function and inside the class itself (meaning set the variable as the property of that class) such variable (AKA property) will be accessible within the body of any function in that class! So any functions in that class can access the property, get its value or change it if necessary.
Alright, now let’s see in details the scope of variables when we declare them in different places.
Scopes of Variables in Kotlin
In short a variable can have any of these three scopes:
- Class scope (AKA member variable)
- Function scope (AKA local variable)
- Block scope
Note: we have a global scope as well, which we’ve explained it in the Kotlin global and local variable section.
Kotlin Class Scope (AKA Properties)
A variable that is declared within the body of a class but outside the body of any function in that class has the Class Scope. (Note: we call such a variable as property!)
This type of variable is accessible within the body of any function declared inside the class. This means one function can, for example, call the variable and change its value if it wants to and another function can simply call the value to get its current value.
Example: class scope variable in Kotlin
class Employee{ var name = "John Doe" fun getName():String{ return "The name is: $name" } fun setName(fullName:String){ name = fullName } }
Here the name
property is declared inside the body of the class and so its scope is Class Scope.
This means every function in this class (getName() and setName()) are able to access the property and get and change its value if they want.
Kotlin Function Scope (AKA Local Variable)
A local variable is a type of variable that we declare within the body of a function! The scope of this variable is limited to just the function that is declared within! Meaning you can’t access the variable from another function! Any attempt to do so would result an error.
Function Scope Notes:
- In a function, we can’t have two variables with the same name!
- But we can have two variables with the same name as long as their scopes differ from each other. For example, you can have a local variable with the name
age
and a property with the same name! - Two functions can also have variables with the same name. This is because each variable is declared in a separate function and so its scope is independent from the other.
Example: Function Scope Variable in Kotlin
class Employee{ fun funcVar(){ var name = "Jack Bauer" } fun printName(){ println("The name is: $name") } } fun main(){ var emp = Employee() emp.printName() }
Output:
unresolved reference: name
In this example, there’s a local variable with the scope of function declared in funcVar
function and named name
. Now within the body of the printName()
function, we’ve tried to access this variable and send its value to the output stream. But we can see that we got an error instead!
This is again because the scope of the variable is limited to its enclosing function and not the other functions! And so for this reason we got the error you see on the output stream.
Kotlin Block Scope (AKA Bracket Scope)
A block scope variable is a variable that is declared within the body of a block {}
. For example, this block can be the block of an if statement, for statement, while statement, etc.
Each of these statements has its own block and if we declare a variable there, we can only access the variable within that boundary! Outside the boundary, it’s as if the variable did not exist at all!
Example: block scope variable in Kotlin
class Employee{ var name = "John Doe" fun printName(){ if (true) { var name = "Jack Bauer" } println("The name is: $name") } } fun main(){ var emp = Employee() emp.printName() }
Output:
John Doe
Here within the body of the printName() function we have a block scope variable that is defined within the body of the if statement. But as you can see, when we called the function to get the value of the name
variable, we got the value John Doe
which is the value of the property of this object!
Again, this is because the variable we’ve defined inside the if statement is limited to the border of that if statement and after that, it’s like the variable didn’t exist at all.
Shadowing Variable in Kotlin
Shadowing a variable happens when we have a local variable in a function with a name that a property of that class also has. In a situation like this, if we try to call the variable in the function, your program will invoke the value of the local variable instead of checking the value of the property of the class!
This is because our programs, when it comes to searching for a variable to get or change its value, they first start with the closest scope for the target variable!
For example, if we call for a variable within the body of an if statement, the program first start looking for the variable inside the body of the if statement itself!
Now if there wasn’t such a variable in the block, then the program will move one step out to see if the enclosing scope has such variable! If that scope (let’s say it’s the scope of a function that is declared inside a class) didn’t have the target variable, then our program continues to search for the variable in the enclosing scope of the function (which in this case it would be the class scope).
Now if the class also didn’t have a variable (property) with the specified name (including the search in the parent classes which we will explain this topic in the Kotlin inheritance section), then we will get an error.
But if the target variable was declared inside the enclosing function, for example, then our program will immediately use that variable to resolve the operation. So it won’t continue to search for the variable inside the body of the class (property). This is where variable shadowing happens.
Example: shadowing variable in Kotlin
class Employee{ var name = "John Doe" fun printName(){ name = "Omid Dehghan" println("The name is: $name") } } fun main(){ var emp = Employee() emp.printName() }
Output:
The name is: Omid Dehghan
Here the printName()
function has a local variable named name
and also we have a property with the same name.
Now when we called the function printName() we got the value of this local variable name
and not the property with this name. (Basically, the property name is shadowed by the local variable we’ve declared in the function)
Again, this is because of the way our program searches for variables in a program.
Kotlin this Keyword
We mentioned how variable shadowing can happen in a function, but if we really want to access the value of a property in a class, Kotlin has provided a keyword called this
which we can prefix the target variable’s name with this keyword and it signals the program that the target variable is actually the object property and not the local variable!
The this
keyword is a reference to the current object that is invoking the target function!
For example, let’s say there’s an object named emp
and it has a function named printSalary()
. Here, if you call the printSalary()
function using the emp object like emp.printSalary()
, calling the this
keyword inside the function would refer to the emp
object.
Now let’s say the object has a property named salary
.
So if we run a statement like this in the printSalary() function:
this.salary
It means we want to access the value of the salary property of the emp
object.
(To make it simple, think of the this
keyword as a variable created automatically for you and it refers to the object that invokes the target function).
Example: using the this keyword in Kotlin
class Employee{ lateinit var firstName: String lateinit var lastName: String var salary:Double = 0.0 fun setNameAndLastName(fName:String, lName:String){ firstName = fName lastName = lName } fun getNameAndLastName():String { return "The name is: ${this.firstName} and the last name is: ${lastName}" } fun putSalary(salary:Double){ this.salary = salary } fun giveSalary():Double{ return this.salary } } fun main(){ var john = Employee() john.firstName = "John" john.lastName = "Doe" john.putSalary(50000.0) println(john.getNameAndLastName()) println(john.giveSalary()) }
Output:
The name is: John and the last name is: Doe 50000.0
Here we’ve used the this
keyword in multiple functions of the Employee
class and in every one of them, the this
keyword will refer to the object that will invoke the enclosing function. Now take a look at this function, for example:
fun putSalary(salary:Double){ this.salary = salary }
This function used the word salary
for its parameter. But we know that there’s a property with the same name as well.
The purpose of this function is to take a value from users and assign that to the value of the salary property.
Now let’s say we didn’t use the this
keyword to differentiate between the object’s property and the parameter of the function:
fun putSalary(salary:Double){ salary = salary }
The problem here is that there’s no way for us (developers) as well as the Kotlin compiler to figure out which salary
name is pointing to the property of the object and which one is pointing to the parameter of the function! Hence, an error will be thrown!
This is what the this
keyword is trying to solve!