Lecture thumbnail 0:00 / 0:00 All right.
We’re now going to take a look at a more complicated implementation of the visitor.
And the example we’re going to take a look at is the visitor builder.
So why would you want to have a visitor builder in the first place.
Well the answer is very simple.
So in most situations you use a builder to construct something uh, ad hoc, meaning that at some point
you need a visitor for something and you don’t want to sort of predefine that visitor ahead of time.
You want to use that visitor in a particular location and be done with it once you’re done, in the
sense that you don’t want the visitor to persist, you don’t want to make additional classes for it.
You just want to construct something in place.
And thanks to a small amount of functional programming, we can actually do that.
And I’m going to show you how we can set up a visitor builder.
So first of all, let’s come back to our example.
I’m going to keep it very simple here.
So we’re going to have a public abstract class expression.
this is not going to have any members.
And then we’ll have the same scenario that we had previously.
So we’re going to have a class called double expression.
That takes a value and it’s going to inherit from expression and which is going to store this value.
So we’ll have let’s say public read only double value equals value.
And then we’ll have addition expression.
So we’ll have a class addition expression.
Let’s have the constructor in line here.
So expression left expression right something like this inherit from expression.
Here we go.
So we’ll have public read only expression left equals left and right equals right like so okay so this
is fairly simple stuff.
This is what we’re going to be working with.
We may as well you know make additions to to this whole thing.
And by the way it needs to be um I’m just gonna update the C sharp language version here, so everything
is okay.
We’ll have similarly a multiplication expression, which is also going to have left and right multiplication
expression with the left expression and the right expression.
Okay.
So far so good.
And what we’re going to do now is we’re going to make a visitor builder.
But before we do that we’ll have some sort of visitor interface.
So the idea is as follows.
We’ll have a visitor builder and it’s going to build something that is going to be called let’s say
built visitor.
So that’s we’re going to be using the builder.
And then it outputs a built visitor.
And you can call some methods on it.
Now what methods.
Well let’s define an interface for it.
So we’re going to have a public interface called visitor.
Now this visitor is going to define the um type as well as the type of the result.
So the idea is that uh depending on what the visitor does, the result could be something like a string
or an int or something to that effect.
So that’s what we’re going to do.
We’re going to have a method called visit which takes some visitor.
And this is a critical point by the way.
We’re going to have a method which just takes a particular node.
So it’s going to be to some some node that we take that we visit.
But in addition we’re also going to have a visit method which takes the visitor itself as a parameter.
Now let me just type this out so that you can see what’s going on.
So we’re going to have a visit which takes an I visitor to result visitor and also the node.
And we’ll see later why this is relevant why this is useful.
It’s actually just a piece of syntactic sugar but it’s useful later on.
Okay.
So what we’re going to do first is we’re going to be constructing a visitor builder.
So some public class visitor builder uh with tea and tea T result as always.
So T is going to be the type that we’re actually visiting, and t result is going to be whatever it
is that we’re outputting.
So let’s have a static constructor here.
So public static visitor builder uh result.
Uh let’s go with new just uh, making it easier to create one.
And then we’re going to have a bunch of visitors inside a dictionary.
So we’re going to have a private read only dictionary where we’re going to have a type.
Notice this is system dot type.
And for every given type we’re going to have some function.
So we’ll have a function which takes an I visitor.
Uh t comma t result.
It takes t and t result.
And this is going to be the set of visitors that we’re going to be storing.
So the visitor builder is essentially going to be a collection of functions which know how to construct
something, and you can also add a default if you want.
So you can have some sort of private func t comma t result or rather I.
Visitor I visitor comma t result.
Um, let’s call it, uh, default visitor.
Just in case.
So the default is going to be called if you don’t have an.
Appropriate visitor for a particular type.
So now what we’re going to have is.
We’re going to have a method called for.
So the idea is that you’re going to be.
Able to define a visitor for a particular type.
And we’re going to do it like this.
So public visitor builder uh t comma t result.
So it’s going to be a fluent interface.
Obviously the result like so.
And we’re going to call it for.
So here uh, for a given t node, uh, what we’re going to be taking is a function which is uh, this
whole function right here.
So this this rather complicated interface goes in here that’s going to be called visitor.
And we need to constrain that t node inherits from T.
So this is important because we want compatibility between the type here and the uh the T node that
is specified here as a type parameter.
So all we have to do here is add it to the dictionary.
So we made this dictionary.
We’re going to add this visitor to the dictionary.
So we just say visitors add uh type of t node equals.
But here on the right hand side we want some sort of function obviously.
So we want some sort of function which takes a visitor and it takes a particular node.
And what it does is it calls visitor on this node.
But of course we need to cast to the node to the type T node like so.
And then we return this because remember we want a fluent interface.
So this four method is going to be the building block of the visitor builder, because we’re going to
be using it quite a bit to add the different handlers.
Okay.
So once we’re done, once we’re finished, we’ll have the build method.
So this is going to return an AI visitor uh visitor TT result.
It’s going to be called build like so.
And I’m getting weird generated defaults here.
And what we’re going to return is a new type called Built visitor.
We haven’t defined it yet of course.
So build Visitor is going to take a bunch of visitors.
And it’s going to also take the default visitor.
And it’s going to, um, essentially, uh, provide an interface where we can actually do stuff, but
we also need to handle this business of the default visitor.
So perhaps defining something like just a sort of default method.
So also a fluent interface will have visitor builder uh t comma t result.
It’s going to be called default.
And it’s going to take a.
Let’s actually put this on a new line because these things are getting rather long here.
So it’s going to take a func just like this one.
It’s oh let’s not forget the letter F here.
And it’s going to be called uh let’s see.
It’s going to be called let’s say visitor.
So this is the visitor that we are taking.
So here all we have to do is we say default visitor equals visitor and then return this.
That’s pretty much all that we need to do.
So this is a visitor builder that you use to construct a visitor for a particular interface.
And then we have to define built visitor.
So build visitor is also going to be an eye visitor.
So we’re going to have uh let’s have a uh private class built visitor, uh, which is going to be an
eye visitor.
And by the way, this is something that is rather important.
What we can do is we can actually take this built visitor and we can stick it inside visitor builder.
So instead of having it as a kind of a publicly available class, because you can’t have private on
the top level.
So let’s just take all of this out and let’s put it in here.
So we’re going to have a built visitor which is going to also implement eye visitor of t comma t result.
Here we go.
So what we need to store first of all is the set of visitors that we got from this location.
So here we have a dictionary.
And I’m just going to copy and paste it here.
We’ll just copy the reference over.
We also need the default visitor here.
Default visitor like so.
There we go.
Okay.
So um, now we need to implement AI visitor because, uh, it’s actually something that we also, um,
let’s just generate this and let’s take a look at what the, the methods are.
So there are two methods, one which takes a t node and another one which also takes the cell.
So let’s implement this uh, visit.
First of all, this is actually easy because we just say visit this comma node like so.
We can even simplify it to an expression body.
And then all we have is this implementation of visit.
So what happens here.
Well for a given node we first try to take the node’s type to see whether or not it can in fact be handled.
So we say var type equals node get type.
So yeah we’re using reflection here.
And if visitors uh has this type.
So if visitors try get value type out var visitor.
So if we manage to get a value from the dictionary, then we return a call to visitor and call it visitor
where the first parameter is self.
Uh, sorry about that.
Let’s actually call it just self like so.
So the first parameter is self.
The second parameter is the node that we’re processing.
Or failing that we just return default visitor self comma node.
So fairly simple stuff.
We look into the dictionary and then we pull out uh whatever uh whatever stuff we actually need.
Okay.
Uh, let’s just, um, let’s just verify that, um, everything is functional.
Uh, we need a constructor somewhere here.
C or F generates, uh, the appropriate constructor.
Except that I also want the default visitor, which for some reason wasn’t generated for me.
Maybe because I didn’t, uh, make the default visitor.
Read only.
Let me try this again.
This is actually a quirk of the IDE.
Let’s try this again.
C or F?
I’m just too lazy to type this stuff out, but unfortunately it looks like I’ll have to type this out.
So here I would have to just copy this and paste it here and say, oh wait, no, the default visitor
got copied.
It’s the other one that we want, the one with the dictionary.
Sorry about that.
So it’s this.
Let’s just paste it in here and then say this.
Visitors equals visitors like so.
Okay.
So we are we’re almost good to go essentially in terms of trying this whole thing out.
Because I’m sure you’re wondering what exactly does all of this do.
So let’s make a very simple expression.
Let’s make an expression here.
Addition expression where the first parameter is let’s say a double expression with a value of let’s
say five.
And the second is a multiplication expression with the values of three and two.
Like so.
So just to type this out we’re essentially adding five and the result of three times two.
So that’s five plus six.
So that should be 11.
And we’re going to see how we can both evaluate this expression as well as print this expression.
So let’s do the printer first.
So you’ll see how this whole interface actually gets used.
So we’re going to say var printer equals.
And then we call visitor builder.
So we’re going to say visitor builder expression comma string.
So notice here the type argument.
So the expression is what we’re operating on.
We’re operating on the hierarchy of expressions.
And string is the result we want because we’re making a printer.
So a printer outputs a string that we can subsequently print.
So we say visitor builder expression comma string dot new.
So that is our static constructor there.
And then let’s just go to the new line.
We’ll use the four method.
And first we’re going to handle double expressions.
So for double expression.
So for double expression we take two parameters.
So first is the visitor and then it’s the double expression.
We don’t need the visitor but we do need the double expression.
And we return double expression dot value dot string.
And I think I forgot to make value public.
Let’s take a look right here.
So double expression.
Uh no it really looks like it’s public.
So I wonder what’s going on here.
Maybe maybe some spelling error.
Let’s try this again.
Double expression like so.
So D and there we go.
There’s a slight error here.
So now for a double expression.
What we’re doing is we’re going to take the value and just turn it to a string.
So that’s easy.
Now given that this is a fluent interface, we can call the form method again.
So we can say for and this time around we’ll take an addition expression.
So for an addition expression we just need to take the left and right sides and put a plus in between
them.
So here the parameters we take we take the visitor.
So this time around the visitor is actually important.
And the second parameter is the addition expression.
Now notice the first parameter is a visitor which explains why when we were making the interface in
the first place here in the visitor we actually have two overloads.
We have one which visits a node, but we also have an overload which takes the visitor itself as the
first parameter.
So this is why.
Because we can now use it in a method such as this.
So here let’s just jump to a new line.
What we have to do is we have to visit the left and right hand sides.
So we have some expression plus some other expression.
And inside these expressions what we do is we say v dot visit.
So we visit uh providing uh the expression as well as the left side a e dot left.
And similarly we say v dot visit uh again with curly braces, a dot.
Right.
Like this.
So, uh, this is, uh, fairly simple stuff and we can replicate this.
So I’m going to just duplicate this and take it to a new line, because we can do this for the multiplication
expression.
It’s not really that difficult multiplication expression.
So a similar thing here.
Just visit the left and the right side.
Except that instead of plus it’s going to be multiplication here.
So this is for printing something.
So then we call just build.
And we have our printer um And, uh, what we can do is we can say var print equals print dot visit.
Expression and print will have the actual string result of how this thing gets printed.
Now similarly what we can do is we can build an evaluator.
So we can say var evaluator equals.
So once again visitor builder uh expression.
And then double because we’re going to evaluate the expression dot new.
So this time around we’re using uh we’re going to have double.
So for double expression we just take the value.
That’s fairly obvious.
And for let’s say an addition expression, uh, we’re going to take um, the left and right sides.
But we have to visit them of course.
So we say v dot visit.
Left side plus v dot visit.
Uh, the uh right side.
And similarly we can do this for multiplication as well.
So for multiplication expression.
For multiplication expression we just multiply the two values and then we build the visitor as well.
So now we can also evaluate this whole thing.
So we can say var value equals evaluator dot print expression like so.
And then let’s take a look at what we what we get as the end result.
So here print equals value.
Let’s actually run this and let’s take a look at what we get.
Except this should be visit.
Sorry about that.
So here we go.
Let’s run this.
Let’s see what the end result is.
As you can see five plus three times two equals 11.
So everything is working correctly.
Play Play Play Play Play Play Play Stop Start Play information alert