So you might be wondering why we’re having to jump through this hoop of a double jump between the visit
and accept methods.
Why can’t we just make an overload and make sure that this overload works correctly?
So let me show you what would be probably the most ideal case.
We’re going to get rid of hi expression, visitor and everything that is related to it.
So I’ll get rid of the accept methods and we’re going to see how we can actually add that same functionality
on the side with the appropriate dispatch happening.
So I’m going to get rid of everything that we’ve done in the expression printer hierarchy and we’re
going to do this again.
But this time round we’re going to do it differently.
So first of all, I’ll show you what it is that we want to achieve ultimately, because ultimately what
we want is something like the following.
We want an expression printer which has public void print edition expression A and Stringbuilder string.
Come on.
Visualstudio Stringbuilder SB And we want a similar thing for the actual double expression.
So we want the same thing for double expression.
And then the question is, well, how do you implement addition expression?
Because typically the way you do this is you say SB dot append with the opening round bracket and then
you say something like print and you say addition expression, dot left, comma.
SB left comma.
SB There we go.
Okay, As you can see, this doesn’t work.
The reason it doesn’t work is because e dot left is of type expression and we don’t have a single overload
which takes an expression.
We only have concrete implementations like addition expression, double expression and so on, and there
is no way for us to persuade the runtime that all of these are going to be non-abstract.
So we cannot do this, we cannot invoke this, but in actual fact we can through a hack.
So let me finish off the implementation of both of these actually.
So I’ll put the implementation in here.
And then of course for print we’re going to have SB dot append dot value.
Wear this for some reason got called a.
It should be called D.
There we go.
Okay, so we want something like this.
And the reason why it works, the reason why it will work is because of this little trick I’ve made
here.
Notice that what I’m doing is I’m taking the left and right hand sides and I am adding a dynamic cast.
Now, the implication of this is that whenever we actually perform this call, the call to print at
runtime what’s going to happen is manifold.
So first of all, the system will take a left and it will treat it as a dynamic object.
Now remember, the whole dynamic thing is primarily done to support the languages which are weakly typed,
which don’t have a type.
But in this case, it’s going to be somewhat something of a reverse because what it’s going to do is
it’s going to try to call the print function where the type of a left having been cast to dynamic matches
what a left actually is.
And in this case, amazingly enough, it’s going to find the correct overloads.
It’s going to call the correct print method.
So let me just prove to you that it works.
I’m going to say var.
Let’s say var EP equals new printer expression printer here, and let’s make SB new Stringbuilder.
And then of course we say EP dot print.
And here notice I cannot pass E and SB That’s not going to work either because once again we have that
same problem.
It’s weird that it’s not being highlighted as an error though, and the reason is that it’s an additional
expression.
So I guess that’s okay because we have an overload for an additional expression.
However, if I do it like this.
Then all of a sudden it becomes a problem once again.
And once again we can use dynamic dispatch by adding that dynamic cast to make sure that we’re calling
the right thing here.
Okay, so having made this invocation, we can writeline the stringbuilder once again.
And this will luckily actually do the right thing and print the right result to the command line.
Okay, so what are the advantages and disadvantages of this?
The advantage is we’re not doing a double hop from except to visit.
We don’t have any kind of visitor interface that we have to implement and the classes are left untouched.
So that’s the upside.
We can make a bunch of these overloads and that’s fine.
But there are downsides.
First of all, performance.
Once you start working with dynamic types, you end up taking a massive performance penalty.
And I have an entire product written using the dynamic visitor approach.
And let me tell you, it does take quite a bit of time to resolve complicated trees.
When you cast everything to dynamic, it’s quite simply not a good idea from the performance perspective.
The second problem is if you are missing something, if you are missing, for example, a print overload,
you’re not going to know.
So let me show you something.
I can comment this out.
I can build the project and everything builds.
How is that possible?
Well, it’s possible because nobody’s actually type checking these.
They’re being cast to dynamic so they can be virtually anything.
And nobody knows that there might be a double expression there that we’re not processing because we
don’t have the right overload.
And then, of course, the only way to find out is you execute this program and you end up, predictably
enough, with a runtime binary exception.
And this runtime binder exception basically tells you, Oh, well, I tried looking for the overload
of print and I didn’t find any sorry about this.
So this is problematic because it’s going to blow up at runtime and in my case, because I’m processing
Excel spreadsheets in this, in this approach, I do actually have it blow up from time to time because
I’m exploring a very large hierarchy of types and some of those types I haven’t covered with the overload,
so it just blows up in my face.
Not very nice.
The last problem, and hopefully it should be obvious as well, is the problem of inheritance.
Let’s suppose you have double expression and then from that you inherit and you have some super double
expression or something.
Well, the problem with this is that when you perform this dispatch, it’s generally going to look for
the type which kind of ignoring the the whole inheritance hierarchy business.
So it can get quite messy from this perspective as well.
I suppose to a degree it’s also valid for an ordinary visitor as well.
But this whole thing of inheritance is also problematic and you have to watch out for and take according
appropriate measures if you do encounter these types of situations.
But this is an extra possibility that has been made possible by the Dynamic Language runtime, and you’re
welcome to use it on small examples.
But if you’re doing large scale stuff like I am, then you may end up with a massive performance hit.
And you need to basically think about whether you’re okay with it or not.
Play Play Play Play Play Stop Play Play Start Play information alert