Hello.
We are now at the last video of this section interpreter design pattern.
Previously we learned about the memento design pattern in this video.
We will learn to create a reverse Polish notation calculator using the interpreter design pattern.
Now we are going to dig into a quite complex pattern.
The interpreter pattern is in fact widely used to solve business cases where it's useful to have a language
to perform common operations.
Let's see what we mean by language.
The most famous interpreter We can talk about is probably askew.
It is defined as a special purpose programming language for managing data held in relational databases
as well as quite complex and big but all in all is a set of words and operators that allow us to perform
operations such as insert select or delete.
Another typical example is musical notation.
It is the language itself and the interpreters the musician who knows the connection between a note
and its representation on the instrument they are playing in computer science it can be useful to design
a small language for a variety of reasons like repetitive tasks higher level languages for non developers
or interface definition languages.
That is Ida L. such as Protocol Buffers or Apache thrift.
Designing a new language big or small can be time consuming so it's very important to have the objectives
clear before investing time and resources on writing an interpreter of it.
So here are a few objectives of the interpreter design pattern.
Firstly it provides syntax for very common operations in some scope such as playing notes.
It allows having an intermediate language to translate actions between two systems.
For example the apps that generate the G code needed to print with 3D printers.
It is is the use of some operations in an easier to use syntax as QoL allows the use of relational databases
in a very easy to use syntax.
But the idea is not to need to write your own functions to make insertions and searches.
A very typical example of an interpreter is to create a reverse Polish notation calculator.
For those of you who don't know what the Polish notation is it's a mathematical notation to make operations
where you write your operations first and then the values.
So plus 3 4 is equivalent to the more common 3 plus 4 and its results would be 7.
So for a reverse Polish notation you put first the values and then the operation.
So 3 4 followed by a plus sign would also be 7 for our calculator.
The acceptance criteria we should pass.
Consider it done or listed here.
First create a language that allows making common arithmetic operations like sums subtractions multiplications
and divisions.
Next it must be done using reverse Polish notation.
Also the user must be able to write as many operations in a row as they want.
And lastly the operations must be performed from left to right.
So the 3 for some 2 subtraction notation is the same as 3 plus 4 in parentheses minus 2 and the result
would be 5.
Now let's start with the unit test of some operations.
In this case we will only have a public method called calculate that takes an operation with its values
defined as a string and will return a value or an error.
I've created a folder named interpreter let's open the interpreter dot go file.
And here we first add the package name import statement and calculate function.
So we will send a string like three four plus to the calculate method and it should return seven nil.
Two tests more will check the correct implementation.
Let's save the file and move to the interpreter test.
Don't go here we write the function test calculator for our unit test.
Wait we need to add the package name and import testing at the beginning of the code.
Go first.
We are going to make the operation we have used as an example.
The 3 for some 2 sub notation is part of our language and we use it in the calculate function.
If an error is returned the test fails.
Finally the result must be equal to 5 and we check it on the last lines.
The next test checks the rest of the operators on slightly more complex operations.
Let me add a few more lines of code and explain it to you here.
We repeat the previous version with a longer operation like the notation 5 minus three.
The hole into 8 and then adding this product to 4 and dividing the whole value by 5 which is equal to
4 let me show you how it could be simplified from left to right the tests must fail of course.
So after saving the changes made to the file let us run the test go to the terminal and run the command
go test hyphen V.
As expected the test failed.
Implementation is going to be longer than testing time to start.
We will define our possible operators in constant let's open the interpreter dot go file.
Here we define the constants and include SDR conf strings and F empty in the import statement interpreter
patterns are usually implemented using an abstract syntax tree something that is commonly achieved using
a stack we have created stacks before the course.
So this should be already familiar to you.
Now we add the Polish notation stack type.
Okay here we have two methods.
The push method to add elements to the top of the stack and the pop method to remove elements and return
them.
In case you're thinking that the line asterisk P equal 2 is a bit cryptic we'll explain it.
The value stored in the direction of P will be overwritten with the actual value in the direction of
P asterisk P but taking only the elements from the beginning to the penultimate element of the array
length minus 1.
So now we will go step by step with the calculate function creating more functions as far as we need
them.
So next we create a calculate function.
The first two things we need to do are to create the stack and to get all different symbols from the
incoming operation.
In this case we aren't checking that it isn't empty.
We split the incoming string operations by the space to get a nice slice of symbols that is values and
operators.
Next we will iterate over every symbol by using range but we need a function to know whether the incoming
symbol is a value or an operator.
So let's add the is operator function.
If the incoming symbol is any of the ones defined in our constants the incoming symbol is an operator.
Now let's add the code at the bottom of the code to the calculate function.
Done.
Don't worry about the code added as comment.
We'll explain and use it later.
Now if it is an operator we consider that we have already passed two values so that what we have to
do is take those two values from the stack the first value taken would be the right most and the second
the leftmost.
Remember that in subtractions and divisions the order of the operations is important.
Then we need some function to get the operation we want to perform.
So let's add this function right below where we have declared the constants.
Also remove the calculate function which we added before the get operation function returns a 2 argument
function that returns an integer.
We check the incoming operator and we return an anonymous function that performs the specified operation.
So now our 4 range continues like this.
Let me remove the comments.
The math function variable is returned by the function.
We use it immediately to perform the operation on the left and right values taken from the stack and
we store its result in a new variable called rez.
Finally we need to push this new value to the stack to keep operating with it later.
Now here is the implementation when the incoming symbol is a value the piece of code which you see as
a comment.
Let me included as code.
Cool.
What do we need to do.
Every time we get a symbol is to push it to the stack.
We have to pass the string symbol to a usable end type.
This is commonly done with the s t r conf package.
By using its 80 o I function the API function takes a string and returns an integer from it or an error.
If everything goes well the value is pushed into the stack at the end of the range statement.
Just one value must be stored on it.
So we just need to return it and the function is done.
That's what we do with the last line of code which you see as a comment.
Let us include this too as code.
Finally let's have a look at the whole code before we run the test.
Okay.
We don't need def empty for now time to run the tests again.
Save the file and move to the terminal type.
Go test hyphen v grade.
We have just created a reverse Polish notation interpreter and a very simple and easy way.
We still lack the parser but that's another story in this example we haven't used any interfaces.
This is not exactly how the interpreter design pattern is defined in more object oriented languages.
However this example is the simplest example possible to understand the objectives of the language and
the next level is inevitably more complex and not intended for beginner users with a more complex example.
We will have to define the type containing more types of itself a value or nothing with a parser you
create this abstract syntax tree to interpret it later.
The same example done by using interfaces would be as in the coming part of this video we will now have
the interpreter pattern again using interfaces.
The main interface we are going to use is called the interpreter interface.
This interface has a read method that every symbol must implement lets open the interpreter dot go file
and write the interface.
Here we first define the main package and import strings and s.t. are icons.
Then we have declared constants sum and sub.
And over here we have the interpreter interface.
We will implement only the sum and the subtraction from the operators and the type called value for
the numbers.
So let's add the code for it.
The value is a type int that when implementing the read method just returns its value.
Next we add the operation sum struct the operation sum struct has the left and right fields and it's
read method returns the sum of each of their read methods the operations subtract struct is the same
but subtracting.
Similarly let us create the operation subtract struct.
We also need a factory pattern to create operators.
We will call it to the operator factory method.
The difference now is that it not only accepts the symbol but also the left and right values taken from
the stack.
So now we add the operator factory method as we have just mentioned.
We also need a stack.
We can reuse the one from the previous example by changing its type.
Let's do it right now.
Here we have our Polish notation stack type now the stack works with the interpreter pointers instead
of int but its functionality is the same.
Finally our main method also looks similar to our previous example.
So now we move ahead to add the main method.
Like before we check whether the symbol is operator or value first when it's a value it pushes it into
the stack when the symbol is an operator.
We also take the right and left values from the stack we call the factory pattern using the current
operator and the left and right values that we just took from the stack.
Once we have the operator type we just need to call it read method to push the return value to the stack
to finally.
Just one example must be left on the stack.
So we print it.
Now we're done with everything.
Let's save the file and open the terminal execute the command.
Go run interpreter dot go.
Awesome.
We have the expected output as 5 at the end.
I would like to share a few important points about the interpreter pattern.
This pattern is extremely powerful but it must also be used carefully to create a language.
It generates a strong coupling between its users and the functionality it provides.
One can fall into the error of trying to create a two flexible language that is incredibly complex to
use and maintain.
Also one can create a fairly small and useful language that doesn't interpret correctly sometimes and
it could be a pain for its users.
In our example we have a method quite a lot of error checking to focus on the implementation of the
interpreter.
However you'll need to do quite a lot of error checking and verbose output on errors to help the user
correct its syntax errors.
So have fun writing your language but be nice to your users.
In this section we have dealt with three extremely powerful patterns that require a lot of practice
before using them in production code.
So we started with the template design pattern and then we moved on to the momento design pattern.
Finally we looked into the interpreter design pattern in the next section we will look at visitor state
mediator and observer design patterns.