Welcome back.
In this lecture, you will learn how to extract the dynamic value inside an interface value.
Let's take a look at an example.
First, I'm going to comment out store.print() to keep the output clear.
I'm going to declare a printer.
This variable stores a printer interface value.
Let me print it. As you can see, the zero value of an interface value is nil.
It doesn't store any value yet. As an example,
let's assign it a game value and print it.
It works. As you can see,
you can assign it any value of a type as long as the type has a print method. A game type has a lot of
fields and methods.
For example I can call the discount method like this.
It works.
Now I'm going to call the discount method on the P variable.
After all the interface variable p stores a game value.
However I cannot call the discount method on the interface variable ("p").
It's because the interface variable ("p") is another game value.
It's a printer interface variable so it doesn't let us access the discount method.
Let's talk about this a little bit more let's create a game variable.
This is what the Tetris variable looks like.
It is a pointer to a game value and it has two methods on it.
Print and discount you can call the print method it works.
You can call the discount method as well.
It also works so far so good.
Now let's see what happens when you put it into a printer interface value.
When I do so the interface value wraps the game value.
Remember from the previous coding example that the variable p stores the interface value.
I can call the print method on it.
It's because there is a print method on the printer interface.
However I can no longer call the discount method it's because there is no discount method on the printer
interface as you can see an interface value wraps and hides the wrapped value.
So you can only use the methods provided by the interface.
Actually this is one of the reasons for using an interface it isolates and decouples one part of the
code from another.
If you could access the other methods there wouldn't be any need for using an interface.
By the way the wrapped value inside that interface value is also called a dynamic value.
It's a dynamic value because the value in an interface value can change in the runtime.
You can assign a different value as long as it satisfies the interface so an interface value has two
parts.
The first part is the dynamic value.
It is the value that is wrapped in an interface value.
The second part is the dynamic type.
It is the type of value that you are storing in an interface value.
It is dynamic so you can change it in runtime here.
The type of this interface value is a printer so you can assign it any type that satisfies the printer
interface.
So how can you extract the dynamic value from an interface value to do that.
You need to use a type assertion.
It looks like this when you use it it extracts and returns you the dynamic value the return value is
the real game value that you put into the interface value you get what you put.
This is the interface value you can extract the dynamic value from it.
To do that you need to type the dynamic values type.
This type is dynamic type that is stored in the interface value.
It's like saying I know there is a game pointer in you give me what you are hiding if it's a book you
just need to type book.
If it's a puzzle you just need to say puzzle.
And so on.
Okay let's take a look at an example.
Let's say I want to discount all the games in my store.
So I'm going to call the discount method like this.
However it doesn't exist yet.
So let's create a discount method on the list like so. It takes a discount ratio just like the discount
method in the game type inside I'm going to loop and I'm going to say it.discount(ratio).
However this will make a discount for every item on the list.
But I want to make a discount only to the games.
Besides that this code doesn't work.
But why?
Remember every item on the list is a printer value.
But the printer interface doesn't have a discount method.
So let's add a discount method to the printer interface to solve this problem.
Nice.
Doing so solves the problem.
However now there is another problem in the main function.
Now only the game type satisfies the printer interface.
It's because the other types don't have a discount method.
So let's get back to the list here.
I didn't solve the problem.
Instead I created another problem.
If there is a lot of types that depend on an interface you cannot easily change the interface.
So what should I do?
First of all let's remove the discount method from the interface.
Now I am back to where I started.
I know that only the game type has a discount method.
So I'm going to extract the game type using a type assertion.
Look I've got a game value and it has a discount method on it.
Let's call it these will only discount the game prices.
Let's try it. Oops!
My program has crashed I'm so unhappy now.
What should I do?
Let's read the error message first.
It says that the printer is a book not a game.
What does that mean?
Well if you think about it a little bit more you can see that there are many types on the list the game
type is only one of them.
Here I make a discount to every item not only to games.
So what should I do now?
How can I check whether the next item is a game or not?
This is where the type checking comes into the scene.
I can check whether the asserted value is a game or not.
To do that I'm going to add a boolean variable here let's print what it does
as you can see it only returns true when the next item is a game pointer let's add a condition here
like this so that I can apply the discount only to the game values it works.
Nice now only the games are discounted.
What's next?
Let's say I want to make a discount to a new type as well.
I'm going to add a toy type.
Let's duplicate the game type and I'm going to change the code for the toy type.
Okay.
Ready.
Let's add it to the store.
I'm going to create a Yoda toy value and I'm going to add it to the store.
Nice.
It works.
Let's go to the list.
I could add another type checking here but it would have complicated the code a lot I will need to use
a type assertion whenever I add a new type here.
So it's not a very effective way.
Instead I'm going to show you something else. Instead of checking for a type,
I'm going to check for a behavior.
So I'm going to use a type assertion to check whether the next item has a discount method or not.
Like this. Remember an interface is just a type. Here,
I try to assert whether the next item satisfies this interface.
If the next item has a discount method it will satisfy it.
So the variable G will have a discount method.
That's why I can call it here.
By the way here only the types and method names are necessary.
So I'm going to remove it let's try it it works.
Excellent.
We can make this code more readable.
To do that I'm going to cut the interface type from here and I'm going to declare it as a discount or
interface type.
Like so.
Lastly I'm going to assert for the discounter type as you can see you don't have to declare an interface
at the package level.
Let's try it.
Cool.
It works by using a type assertion.
You can also check whether a value provides the method(s) that you want or not.
For example here I execute the discount method only if an item value has a discount method.
So here the type assertion doesn't extract the dynamic value.
Instead it converts the printer interface value to a discounter interface value but only if the value
has a discount method.
By the way I can also type the assertion more concisely.
Remember this is just a short if statement here I declare a new it variable only for the short if
statement before the if statement.
The it is a printer however the new it here becomes a discounter using the same variable name is just
a convention in go.
By doing so we also convey the meaning that the it variable is not only a printer,
it's also a discounter.
In summary there are two use cases for a type assertion.
First you can use it to extract the dynamic value from an interface value.
Second you can use it to check whether an interface value provides the methods that you want or not.
See you in the next lecture.