Hi, this is Sriyank Siddhartha and welcome
to another video on Kotlin Fundamentals. Well it is generally seen that developers
face a lot of difficulty while dealing with the Scope Functions. So in this video, we will explore what are scope functions,
what are the types of different scope functions, what are the differences between those scope
functions. Most importantly, when to use them, where
to use them and how to use them in your application. And in the end, I will summarize the video in
the simplest possible way which will add more sense to your understanding. So stick to this video till the end. Let’s get started. Well, there are 5 types of Scope functions. They are, WITH, LET, RUN, APPLY, and ALSO. Before we explore them, let me show you a
gist of how these functions add value to our programs. Suppose this is a class Person... with Two
properties... Name and Age. .. right? So, in general, we would instantiate this class
object as... Create a Person object
And assign values to it... Like this... So no doubt till now.. But let's see the same code using Scope Function. So here.. we create the object. and on that
Object we call the APPLY function. Well, APPLY is a scope function which is Basically
a higher order function. So in the lambda expression attached to it
we will write.. name equal to Sriyank Siddhartha AND Age equal to 26. So in the ordinary code, we have some code
repitition. Right..? But here using Scope function, our code is
more concise and more readable indeed. Just use the apply function and initialise
the properties without using the object name. So in short, the SCOPE FUNCTIONS make your
code clear, CONCISE and mode readable. Fine? Now, coming back to our discussion from where
we left. So now we know that, by using these functions
you can make your program more concise and readable. Let’s explore these functions one by one,
in a step by step process. Now these 5 functions are closely related
to each other. They are all quite similar in nature and quite
often programmers get confused when to use what? So it is very important to understand the
differences between them. So how do we differentiate between the scope
functions. Well, there are two main differences between
each scope function. The first one is the way to refer to the context
object. And this is done using either 'this' keyword
or by using the 'it' keyword. I hope you are aware of these two keywords. The second one is the RETURN value of the
function. These functions either return the context
object or the lambda result. Fine? Well, don't worry we will discuss them, what
are they .... in our demo. For now don't worry about it. So for WITH function, the return type is the
lambda result. and the context object is .... 'this' which
refers to the object itself. To understand things better, let us explore
a simple and sweet demo of WITH function. DEMO WithFunction.kt So here I have defined a very simple class
of Person. With two properties, name and age. Well, I have given default values to these
properties. This is not the appropriate way to assign
values right here but for the sake of simplicity I have done it. Fine? Next, in the main function. I have initialised the class Person and I
am printing the properties of the person object. No doubt till now. But here if you notice, I am repeating the
same person object again and again. Imagine if we have 20 such properties and
10 functions that belong to class Person. In such case, there would be abundance of
code repeatition. So let's see how to avoid it using WITH function. So I will use with and pass the person object
as parameter. And attached to this method is the lambda
expression. and you can access this person object using
this keyword. For example, you can use print and then this.name. Like this. Similarly, you can print the age. Perfect. So I hope now you understand what it means
when we say we can access the context object by using 'this' keyword. Great. Also, you need not explicitly use this keyword
within the lambda expression. You can remove them. Don't worry the code will still work. And now you can delete these two lines. You can run the program and check the output
remains the same. Great isn't it. Now let us come to the second Property. The return value is the lambda result. So what does it mean? Well, this WITH function Basically returns
a result. And that result is the last statement of the
lambda expression. For example, at the end if you write 'age
+ 5', then this value will be returned. That means, Here you can define a variable of the type
Int. So this age + 5 will be returned and stored
in this variable. And then you can use the value in your program...
as per your wish. Now, if you add a String at the end. ... over here.. For example, if you write
"He is a freak who loves to teach in his own crazy way"
Then now this string will be returned from this function. So this age + 5 will do nothing. Instead of this value, this string will be
returned. In short, whatever data is present at the
end of the lambda expression will be returned. So instead of Int, it would be String now. And we can change the variable to ... let's
say... bio And accordingly, you need to update your program. And the term context object refers to the
person Object on which we are performing the operation. Fine? So after WITH function, let's check out the
APPLY function. Well, the apply function returns the context
object itself. Please note this. and we refer to the context
object using 'this' keyword... similar to what we say earlier. So let's see how to use this function. Here we have the class Person with two properties
name and age. And now in our program, after we create the
person object. Suppose we want to initialise the object properties,
then what we usually do? We just initialise them using the object name
... right? But again it leads to code redundancy. So kotlin provides a solution to it. It provides you with the ....APPLY function. So instead of these two statements We can use .apply over here. and within its
lambda expression, we can use and So this clearly shows, the property 1. i.e. you can refer to the person object by
using this keyword. And of course, within the lambda using this
keyword is optional. So if you remove them... your code will work fine. Now what about the second property. Well, the apply function returns the context
object itself. i.e. this whole expression will return the
person object we are creating. So here on the left, we can use val person
equal to... the apply function. fine? If this statement confuses you. then you can split it into two statements. Like this. First create the object and then apply values
to it. Nice and simple. But generally we dont use it this way in two
statements. We do it one liner. Fine? Now, you can then use the with function ofcouse
to print the values. Let us run the program. Perfect. So this is how we use the APPLY function along
with the WITH function. Quite simple isn't it. Moving ahead, let's check out the ALSO function. Well, this function returns the context object. And you can refer to the object by using 'it'
identifier. So let's see how to use this function. Well, this 'also' function is generally used
where we want to perform some additional operation on a particular object after we initialise
it. Let me show you an example. Suppose we create an object 'numbersList'
with initially 3 integer values...i.e. 1 2 and 3 And then we write some other code here.. And then later, we decide to perform some operations on this
numbersList which we have defined here. The operation could be anything, such as print the numbers Add a new number to the list Print the updated list Remove a number And then again print the updated list Then in such situation, we can use the ALSO
function. So what we can do is, use numbersList.also
function and within the lambda expression Just cut all the code and paste them right
here. And as per the Property 1, we can refer to
the context object by using 'it' identifier. i.e. you can refer to this numbersList just
by using 'it'... like this And so here as well, change it to 'it'
Great. Now, if you check the property 2, it says
that, the returned object is the context object itself. So this whole function, will return the same
numbersList which we have defined here [point to code at top] So if you put Then these two variables will point to exactly
same LIST object. let me show you the proof. Let's write print statements for that. Run the program. So these are the print statements from the
ALSO function. And at the bottom, you can see, both variables
are pointing to the same object. How cool is that? So I guess things are now clear. Let us now take another example where we can
use the ALSO function. In this program, where we explored the APPLY
function. Here at the top we have initialised the object
right... then we have some code... And later suppose you want to modify or perform
some operation on the person object which we have created here... then what you can
do is.. At the bottom, just use person.also And then modify the name, and you can print and check the new name as well. And of course this whole function will return
an object reference which will point to the same person object. But generally, while using ALSO function,
we don't keep the reference. So let's remove it. Perfect. So I hope you understand clearly the use case
of ALSO function. Moving forward, we have the LET function. Well, let function returns the lambda result. and you can refer to the context object by
using 'it' identifier. Let's understand it better in a program. Now, the LET function has a lot of application. But I am going to show you the most important
usage of this function. Generally, we use the LET function to avoid
NULL pointer exception. Which is a nightmare for most developers across
the world. Let's see how. Suppose we have a nullable String variable...
name. with the value initialised to null. And we want to perform some operations on
it. such as printing the reversed String value OR printing the capitalized string value Or it could be anything such as printing the length of the name String. And here I am using Not-Null Assertion operator
to assert that my value is not null. Right. And
in case the value is found be null, then this statement will throw NullPointerException. Let us run the program. Here we go, we got NullPointerException. So using let function, you can easily avoid
such terrible mistake. All you have to do is, use the name object
and call the let function on it. And then cut the code, and paste them within
the lambda expression. BUT if you run the program right, it will
still throw NullPointerException at this statement. So along with let, you need to use the Safe
call operator. which is represented by ? followed by a dot. So after name, lets put ? followed by dot. So this statement Basically means that, execute
this code only if the name object is not NULL. Now, once you have taken precaution, you can
remove these non null assertion operator. If you run the program now, we get no output
because since the name is null, therefore this code was not executed. Hence, we are safe from NullPointerException. Now, let's take a look at the property of
LET function. Well, you need to refer to the context object
using 'it' identifier. So let's replace 'name' by 'it' everywhere. and the second property says that, the return
value is actually the lambda result. Which means whatever value we keep at the
end of the lambda expression will be returned. So if we keep it.length at the end, and use a variable length over here. Then the length of the String will be returned
and stored in this variable. Fine? And then you can print the value in your program. Like this. Now, let us test our code. For that, let's change this null to some valid
String value. and run the program. Here we go, this is the reversed string. this is the capitalised string. and this is the length of the String. Pretty awesome. Now, again there are more use cases of LET
function. But trust me usually we use the LET function,
for avoiding NullPointerException. So yes that's all for the LET function. It's time to go ahead and explore our last
Scope Function... i.e. the RUN function. Well, the run function returns the lambda
result and you can refer to the context object by
using 'this' keyword. Now, the RUN function is actually the combination
on the WITH function and the LET function. Now Why I am saying this? For that, let's see the code in action. If you remember, we explored this code while
exploring with function. Here we have the class Person. We created the person object. And Performed some operation using the with
function. Right? the code is quite clear. Now, if we make this Person object as NULLABLE.
by using a question mark over here. And assign a NULL value to it Then we must find a way out to prevent NULL
pointer exception for this piece of code. Right? The best possible solution is to use the RUN
function. So using Run function, you can perform what
this code was earlier performing. And along with it, you can also avoid the
NULL POINTER Exception without writing any extra code. So that is why we say, RUN function is the
combination of WITH function and LET function. To
implement the run function. just use and within lambda expression, put this code. Like this. And just like LET function, just use a Safe
call operator over here. And that is it... you are done. POINTER
And similar to with function, like we can return a lambda result over here... the RUN
function as well, returns the lambda result. So here as well, we can use val bio So this string will be returned and stored
within this variable. And now we can remove this entire code. Perfect. So once again, this code will only be executed
if this person object is not null. Thus preventing the NullPointerEception. Perfect. You can now, use a valid Objector creator
here and test the output yourself. So yes that's all for RUN function. So we have come up a long way to understand
scope functions in this video. And as a beginner, if you are feeling jumbled
or confused about when to use what... then i don't blame you for that. Using scope functions at right place is bit
tricky. So let's summarise this video and give you
a big picture of what we have learnt so far. You can use with function, if you want to
operate on a non-null object. You can use let function, if you want to just
execute lambda expression on a nullable object and avoid NullPointerEception Next, use RUn function, If you want to operate
on a nullable object, execute lambda expression and avoid NullPointerEception Moving on, you can use APPLY function, If
you want to initialise or configure an object And finally, you can use ALSO function If
you want to do some additional object configuration or operations So in future, whenever you feel confused about
when to use what.... just revisit this part of the video. Things will automatically get sorted. So I hope you had a great time learning concepts
in this video. This is Sriyank Siddhartha signing off. Thanks for watching and have a nice day.