Lecture thumbnail 0:01 / 12:01 So you’re probably familiar by now with the classic double dispatch visitor.

That’s the visitor that we got from the Gang of Four Design Patterns book.

Now, it’s not a perfect implementation.

There are downsides to it.

And one of the downsides is that ultimately this visitor is really difficult to modify if you have additional

elements in the hierarchy, for example.

So you have your hierarchy, you have your base class and you have your inheritance.

But the problem is code duplication.

So you require a lot of repetitive code in the hierarchy classes to actually implement double dispatch,

because essentially you need the accept method inside each of the elements.

But in addition you also need the visit method corresponding to every single element in the hierarchy,

like every single one.

And this can be very constraining because essentially imagine the situation where the hierarchy is changing,

where you’re adding additional members or you’re removing a member.

What’s going to happen then?

Well, what’s going to happen is that you’re going to have to change lots of things.

You’re going to need to change.

Well, the visitor, obviously, but you will also need to re-implement every single visitor.

So you’ll need to either add or remove the visit methods and you’ll need to basically modify whoever

it is that actually implements the expression visitor in this case.

So this is a lot of work.

It’s a lot of work.

And we can we can get away from this all by paying a performance cost.

And that is what these acyclic visitor is all about.

So we’re going to take a look at how that actually works.

So the acyclic visitor is actually well, essentially it’s using a bunch of tricks.

It’s using a marker interface and it’s using also generic interfaces in order to allow you to effectively

specify what objects out of the whole array of objects out there that your visitor can actually visit.

So let’s start somewhere.

So we need to define an interface, first of all.

So we’ll define an interface called I Visitor.

But this time around it’s going to be a generic interface, which is going to take a type argument called

T visitable.

So essentially this interface is going to have a single method and this method is going to be called

visit.

So we have visit which takes a t visitable t visitable obj and then we have to implement this I visitor

for whatever this that we’re actually visiting.

We’ll take a look at that in a moment.

Now, in addition, what we do is we add another interface called I Visitor, and this time around it’s

a non generic.

It’s just an ordinary interface without any generic arguments.

And you are allowed to have both a generic and a non generic version.

Now the reason why we’re doing this is we’re using this interface as a marker interface or what Robert

C Martin would call a degenerate class or a degenerate interface.

But essentially this degenerate interface is going to be used simply for indicating that some type is

a visitor.

So essentially you’ll implement this interface without really having to implement any methods because

it doesn’t have any.

Okay.

So now let’s talk about the actual types and how these types would typically accept the visitor in the

first place.

How would you accept the visitor in the case of a particular type?

So let’s suppose that we have some sort of base class or indeed base interface.

I’ll just make an abstract class called expression.

So this is going to represent a numeric expression and essentially we’re going to have two types of

expressions.

You can have a number like three, for example.

That’s going to be a double expression.

And we’re also going to have addition of two elements like one plus 2 or 1 plus, say one plus two plus

three.

And those are going to be addition expressions and they’re all going to have this base class expression

now in the classic visitor implementation, in a double dispatch, what you would be expected to do

is to add an accept method.

And indeed, in this particular case, you can also add an accept method.

But the difference is that you don’t really have to you don’t really have to give any indication as

to what kind of visitor you’re actually getting.

So instead of specifying that you are taking a particular expression visitor, what you do is you just

take an eye visitor and you don’t really care what kind of eye visitor it is.

So in the base class, even though this is an abstract class, I can have a public virtual void method

called accept which takes an eye visitor.

And as you can see, we’re making things very general because I visitor is a marker interface that can

be attached to any visitor you can think of.

So it doesn’t really matter.

Now.

What’s going to happen here is we need to determine whether this eye visitor is actually capable of

visiting an expression.

And the question is, well, how can we test that?

Well, we’ll do an if here.

So we’ll say if visitor is eye visitor of expression and this is going to be a typed visitor, then

we say type dot visit providing this as the argument.

Okay.

So obviously in our example, the base class expression isn’t really visitable by.

By itself, it doesn’t really make much sense to visit something which is abstract.

We might want to visit the derived types, but it’s also interesting that you can do this.

You can have an accept method for the base class that you can subsequently specify a visitor for.

But much more interesting are the visitors for the double expression and the addition expression.

So that’s what we’re going to take a look at.

So first of all, we’ll have a class called Double Expression.

So a double expression is going to inherit from expression.

And here we’ll have a double value, public double value, and I’ll have a constructor which initializes

this value.

And then, of course, what I can do is I can take the accept method here and I can override it.

So essentially what I can do is if I type accept like so I can perform the override, except that instead

of just calling the base, what I’m going to do is similar to what we’re doing here.

I’m going to copy this.

But of course the kind of visitor that we’re interested in is an I visitor of a double expression.

So if a visitor can take a double expression, then yeah, that’s that’s okay.

But if it doesn’t, then it’s a no op.

It’s basically no operation happening here.

So let’s set a class for addition expression.

So in addition to expression also inherits from expression.

And here we have the left and right hand sides of an addition, and those can be expressions themselves.

So public expression left and right.

And we make a constructor for both of them.

And then of course, once again and I can just do some cut and paste programming here, we can copy

this implementation and put it in the right place, hopefully.

So here you would obviously instead of accepting a double expression, you would take an addition expression.

But apart from that, the implementation is once again the same.

Now you might say, Well, hold on, we wanted to get rid of some of the duplication.

So why you duplicating things here?

Well, I am duplicating things, but remember, we’re doing this in an acyclic way, so there is no

cyclic dependency between the visitor interface and the actual implementations.

So even though those things are, well, they’re still introducing a certain amount of duplication.

It’s not the same kind of duplication in the sense that you can, for example, get rid of a visitor

for a double expression completely and things will still work just fine.

And we’re certainly going to take a look at exactly that in just a moment.

Okay.

So now we need to make a visitor and I want to make a visitor, which actually prints both the double

expressions and the addition expressions.

So let’s have a class called expression printer.

Now, expression printer is first of all, going to implement the mocker interface, which is I visitor,

but that’s not so interesting.

What’s interesting is that it can now specify what kind of types it can actually visit.

So here I can say that I can visit, for example, an expression and I can duplicate this a couple of

times.

Not too many though, and also indicate that I can visit a double expression or indeed an addition expression.

There we go.

Okay, so now I need to implement the accept method for each one of these.

Actually, I think it’s visit.

Is it visit?

Let’s take a look.

Yes, of course I’m right.

It’s visit.

So as you implement all of these visit methods, what you can do is you can make decisions as to what’s

actually going to happen as you process these types of expressions.

Now, for the route type, I don’t think we’re ever likely to come here because essentially what we

want is we want the concrete implementations to be processed, like for example, for the double expression,

for example.

So I’m going to leave this empty, but this is a good location for you to perform some error handling,

for example, or you can have a non abstract base type in which case everything is okay.

But we’re interested in printing double expressions and addition expressions.

So for the double expression, the printing is actually very easy.

Let’s make a stringbuilder here so I’ll have a private Stringbuilder SB equals new Stringbuilder like

so.

And here what I’m going to do for the double expression is I’m going to say SB dot append and I’ll append

obj dot value.

So that’s the value that I’m going to append.

And for the addition expression, what we want to do is we want to put round brackets around the expression.

So I’ll say SB dot append and I’ll put an opening round bracket and I also have a closing round bracket.

I’ll have the plus in the middle.

And then of course we have to visit the left and right hand sides of this addition expression and this

is very easy to do.

So we can say obj dot left dot, accept this.

Now notice it looks very much like a double dispatch visitor.

The only difference is that when you call accept what’s going to happen is somebody will actually verify

that the kind of visitor you’re passing in is capable of processing expressions, is capable of processing

double expressions, is capable of processing addition expressions depending on what you what the actual

argument is.

Okay.

So here in a similar fashion we would say obj dot, right dot accept this and that’s how you implement

the actual printer.

So now all I have to do is expose to string public override, string to string.

And here I’m just going to return Stringbuilder dot two string.

That’s how we’re going to roll here.

And then I can actually write the demo where we.

Construct an expression and we actually use it.

So let’s stick a static void main in here.

And now let me show you the expression itself.

I’m going to do one plus two plus three, very simple kind of stuff.

So here is my addition expression.

What I do now is I make an expression printer, just like with a double dispatch, I make a new expression

printer.

And then of course I can say EP dot visit E, So I visit the expression and I can print it out.

So console dot write line EP to string.

There we go.

So this is how you implement an acyclic visitor.

Let’s actually run this and see what we get.

All right.

So as you can see, we’re printing the right thing.

Now, I wanted to show you the flexibility in the acyclic visitor as opposed to the ordinary cyclic

visitor.

So, for example, let’s suppose that you decide to neglect support for visiting double expressions.

I can simply comment out this whole thing.

I can delete this method and surprise, surprise, things are still going to compile and the whole thing

is still going to work.

So let’s compile it and let’s see what we get.

Now, as you can see, everything continues to work.

Now, obviously, instead of the double values, we don’t print anything, but we still have the round

brackets and the pluses.

So this is a good illustration of some of the additional flexibility that is afforded by the acyclic

visitor.

But what you have to realize is there is a certain performance cost here because you’re essentially

checking the type of the visitor before you actually dispatch on the visitor.

So this is an alternative implementation of the visitor, which can be relevant in some development

scenarios.

Play Play Play Play Play Play Stop Play Start Play information alert